【图论】拓扑排序
算法一:
寻找入度为0(没有任何结点指向它)的结点Q,删除Q及与Q相连的边。
重复上述操作直到结点被全部删除,或找不到入度为0的结点(存在有向环,非DAG)。
算法二:
遍历每一个结点,通过DFS访问结点的所有子孙。当前结点无子孙时为递归边界,将结点加入到当前拓扑序的首部。
需要注意的是,要判断递归路上是否有遇到存在有向环的结点,故要用\(vis[u]\)存储结点状态:
\(vis[u]=0\)时,结点\(u\)从未访问过;
\(vis[u]=-1\)时,结点\(u\)正在访问;
\(vis[u]=1\)时,结点\(u\)已访问完毕。
int E[1000 + 10][1000 + 10];
int vis[100 + 10];
int topo[100 + 10];
int n, m, pos;
bool dfs(int V) {
vis[V] = -1;
for (int u = 1;u <= n;u++) {
if (E[V][u]) {
if (vis[u] < 0) return false;//存在有向环
else if (!vis[u] && !dfs(u)) return false;//没访问过的新结点进行访问,但过程中出现有向环
}
}
vis[V] = 1;
topo[pos] = V;
pos--;
return true;
}
bool toposort() {
for (int u = 1;u <= n;u++) {
if (!vis[u] && !dfs(u))return false;
}
return true;
}
int main()
{
while (cin >> n >> m) {
if (!n && !m) break;
memset(E, 0, sizeof(E));
memset(topo, 0, sizeof(topo));
memset(vis, 0, sizeof(vis));
pos = n;
for (int i = 1;i <= m;i++) {
int a, b;
cin >> a >> b;
E[a][b] = 1;
}
if (toposort()) {
cout << topo[1];
for (int i = 2;i <= n;i++) cout << " " << topo[i];
cout << endl;
}
}
return 0;
}