详解:拓扑排序
拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u、v,如果存在边u–>v,那么在序列中u一定在v的前面。
常用于一些需要先满足某些条件的情况。例如,选择课程需要先修过哪些课程才能选择该门课程。
拓扑排序也常用来判断图中是否有环存在。
得到的一种拓扑排序如下:
算法思路如下
- 定义一个队列Q,并把所有入度为0的节点加入队列;
- 取队列首结点,然后删去从它出发的边,并令这些边到达的点入度减去1;如果某个点的入度为0,则将该点入队;
- 反复进行步骤2操作,知道队列为空。如果队列为空时入过队的节点数目恰好为N,说明拓扑排序成功,图G为有向无环图;否则,拓扑排序失败,图G中有环
输入n, m,分别为顶点数和边数
接下来m行u, v,代表一条从u到v的边
输入
9 12
0 3
0 4
0 5
1 5
2 3
2 8
3 6
3 7
4 8
5 7
5 8
6 7
输出
0 1 2 4 5 3 8 6 7
Yes
代码
C++
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//拓扑排序
bool topologicalSort(vector<vector<int>>& G, vector<int>& inDegree, int n) {
int num = 0; //记录加入拓扑排序的结点数目
queue<int> q;
for (int i = 0; i < n; i++) {
if (inDegree[i] == 0) {
q.push(i); //入度为0,加入到队列中
}
}
while (!q.empty()) {
int u = q.front();
num++;
cout << u;
if (num < n) cout << " ";
else cout << endl;
q.pop();
for (int i = 0; i < G[u].size(); i++) { //遍历从u可以到达的顶点
int v = G[u][i];
inDegree[v]--;
if (inDegree[v] == 0) {
q.push(v);
}
}
G[u].clear();
}
if (num == n) return true;
else return false;
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> G(n, vector<int>()); //邻接表
vector<int> inDegree(n, 0); //入度
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
G[u].push_back(v);
inDegree[v]++;
}
bool res = topologicalSort(G, inDegree, n);
if (res) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
Java
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main{
private static int INF = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
int[][] G = new int[n][n];
int[] inDegree = new int[n];
int u, v;
for (int i = 0; i < m; i++) {
u = input.nextInt();
v = input.nextInt();
G[u][v] = 1;
inDegree[v]++;
}
boolean res = topologicalSort(G, inDegree, n);
if (res) System.out.println("Yes");
else System.out.println("No");
}
public static boolean topologicalSort(int[][] G, int[] inDegree, int n) {
int num = 0;
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++) {
if (inDegree[i] == 0) {
queue.add(i);
}
}
while (!queue.isEmpty()) {
int u = queue.poll();
num++;
System.out.print(u);
if (num < n) System.out.print(" ");
else System.out.println();
for (int v = 0; v < n; v++) {
if (G[u][v] != 0) {
inDegree[v]--;
if (inDegree[v] == 0) {
queue.add(v);
}
G[u][v] = 0;
}
}
}
if (num == n) return true;
else return false;
}
}
9 12
0 3
0 4
0 5
1 5
2 3
2 8
3 6
3 7
4 8
5 7
5 8
6 7
0 1 2 4 5 3 8 6 7
Yes