
什么是拓扑排序
对一个有向无环图
(
D
i
r
e
c
t
e
d
A
c
y
c
l
i
c
G
r
a
p
h
简
称
D
A
G
)
(Directed Acyclic Graph简称DAG)
(DirectedAcyclicGraph简称DAG)
G
G
G进行拓扑排序,是将
G
G
G中所有顶点排成一个线性序列,使得图中任意一对顶点
u
u
u和
v
v
v,若边
<
u
,
v
>
∈
E
(
G
)
<u,v>∈E(G)
<u,v>∈E(G),则
u
u
u在线性序列中出现在
v
v
v之前。通常,这样的线性序列称为满足拓扑次序
(
T
o
p
o
l
o
g
i
c
a
l
O
r
d
e
r
)
(Topological Order)
(TopologicalOrder)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
—摘自度娘
简单的来说,我们就找到一个
(
(
(或多个
)
)
)起点,遍历所有能遍历的点,遍历的顺序就是拓扑排序。
模拟
下面是一个有向无环图,我们来遍历一下,感受一下
取出唯一一个入度为0的点—
1
1
1
删除所有连接
1
1
1的边
取出两个入度为0的点—
2
、
3
2、3
2、3
删除所有连接
2
、
3
2、3
2、3的边
取出两个入度为0的点—
4
4
4
删除所有连接4的边
取出两个入度为0的点—
5
5
5
图中已经没有点了,遍历结束
最终的顺序为 : 1 、 2 、 3 、 4 、 5 ( :1、2、3、4、5( :1、2、3、4、5(不唯一 ) ) )
代码实现
BFS
通过上面的描述相信大家都能想到BFS的方法, 我们用一个队列来储存入度为0的点,用 i n [ ] in[] in[]来储存每个点的入度, e d g e [ ] edge[] edge[] ( v e c t o r (vector (vector型 ) ) )来储存边的连接与否。
bool TopoSort() {
queue <int > q;
vector <int > ans;
for (int i = 1; i <= n; i ++) {
if (in[i] == 0) {
q.push(i);
}
}
while (q.size()) {
int U = q.front();
q.pop();
ans.push_back(U);
for (vector <int > :: iterator it = edge[U].begin(); it != edge[U].end(); it ++) {
in[*it] --;
if (in[*it] == 0) {
q.push(*it);
}
}
}
if (ans.size() == n) { //判断是否存在环,如果存在环,就会使得入度为0的点减少
for (vector <int > :: iterator it = ans.end() - 1; it != ans.begin() - 1; it --) {
printf("%d ", (*it));
}
return true;
}
return false;
}

DFS
bool dfs(int u){
c[u] = -1; //标记为正在访问
for (int v = 1; v <= n; v ++)
if (G[u][v]) {
if (nows[v] < 0) { return false; } //正在访问,退出
else if (!nows[v] && !dfs(v)) { return false; } //访问过且访问失败,退出
}
nows[u] = 1; //标记为访问过
ans[-- t] = u; //倒序储存
return true;
}
bool TopoSort() {
t = n;
memset(ans, 0, sizeof(ans));
for (int u = 1; u <= n; u ++) {
if (!ans[u]) { //判断是否未访问
if (!dfs(u)) { return false; }
}
}
return true;
}


被折叠的 条评论
为什么被折叠?



