Sicily 拓扑排序
来源:互联网 发布:沙特王室知乎 编辑:程序博客网 时间:2024/05/17 02:30
题目
在图论中,拓扑序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列. 且该序列必须满足下面两个条件:
- 每个顶点出现且只出现一次.
- 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面.
对于一个含有n个节点的有向无环图(节点编号0到n-1),输出它的一个拓扑序.
图的节点数和边数均不多于100000,保证输入的图是一个无环图.
请为下面的Solution类实现解决上述问题的topologicalSort函数,函数参数中n为图的节点数,edges是边集,edges[i]表示第i条边从edges[i].first指向edges[i].second. 函数返回值为有向图的一个拓扑序. 有向图有多个拓扑序时,输出任意一个即可.
例1:
n = 3,edges = {(0, 1), (0, 2)},函数应返回{0, 1, 2}或者{0, 2, 1}.
例2:
n = 4,edges = {(0, 1), (0, 2), (1, 2), (3, 0)},函数应返回{3, 0, 1, 2}.
代码及解析
一开始使用了一份没有任何优化的方法,具体代码如下:
class Solution {public: vector<int> topologicalSort(int n, vector<pair<int, int>>& edges) { vector<int> res; /* 记录每个点的入度 */ int *inDegree = new int[n]; /* 记录某个点是否已经输出 */ bool *havePop = new bool[n]; for (int i = 0; i < n; ++i) { inDegree[i] = 0; havePop[i] = false; } for (int i = 0; i < edges.size(); ++i) { inDegree[edges[i].second]++; } int count = n; while (count > 0) { int present; /* 找到一个入度为0的点 */ for (int i = 0; i < n; ++i) { if (inDegree[i] == 0 && havePop[i] == false) { present = i; break; } } /* 对要输出的点能到达的每个点的入度-1 */ for (int i = 0; i < edges.size(); ++i) { if (edges[i].first == present) { inDegree[edges[i].second]--; } } havePop[present] = true; res.push_back(present); count--; } return res; }};
显然这种算法的复杂度太高,下面给出一种改进的算法,主要从两个方面改进:
一是用一个队列存储入度为0的点,每次将队列队首的点输出,在将该点能到达的所有点的入度-1时将新的入度为0的点加入队列
二是用一个二维vector作为邻接表存储每个点能到达的所有点,代替每次循环对所有的边进行遍历
具体代码如下:
class Solution {public: vector<int> topologicalSort(int n, vector<pair<int, int>>& edges) { vector<int> res; /* 存储入度为0的点 */ queue<int> inDegreeZero; /* 存储邻接表 */ vector<vector<int>> reach(n); int *inDegree = new int[n]; bool *havePop = new bool[n]; for (int i = 0; i < n; ++i) { inDegree[i] = 0; havePop[i] = false; } for (int i = 0; i < edges.size(); ++i) { inDegree[edges[i].second]++; /* 在更新入度的同时,更新邻接表 */ reach[edges[i].first].push_back(edges[i].second); } /* 找出初始入度为0的点,加入队列 */ for (int i = 0; i < n; ++i) { if (inDegree[i] == 0 && havePop[i] == false) { inDegreeZero.push(i); } } while (res.size() < n) { /* 每次取队列第一个元素输出 */ int present = inDegreeZero.front(); for (int i = 0; i < reach[present].size(); ++i) { /* 判断更新完入度后该点是否入度为0,是则加入队列 */ int tmp = (--inDegree[reach[present][i]]); if (tmp == 0) { inDegreeZero.push(reach[present][i]); } } havePop[present] = true; inDegreeZero.pop(); res.push_back(present); } return res; }};
阅读全文
0 0
- Sicily 拓扑排序
- Sicily 1424 奖金(拓扑排序)
- sicily Ordering Tasks 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 【拓扑排序】
- 拓扑排序
- [UOJ191][集训队互测2016]Unknown-线段树-斜率优化
- 手机端页面所需文件引入
- 给多个jar包起一个别名,用于项目引用
- springboot整合mybatis
- Photolemur(自动化图片处理软件)官方破解版V2.2.0.909下载 | photolemur 破解版
- Sicily 拓扑排序
- 套接字编程常用函数
- 排序-改良冒泡排序
- 排序-直接插入排序
- windows 下redis在后台运行(亲测)
- Oracle误删表的恢复操作
- sdk合并报错:app:transformResourcesWithMergeJavaResForDedug,资源文件/META-INF/MANIFEST.MF重复
- code forces739B 树上差分
- Spring实现事务的处理