基于dfs的拓扑排序

基于dfs的拓扑排序

以每一个入度为0的点为起点dfs,节点回溯时进栈(类似欧拉回路),有反向边说明有回路。

img

  1. 首先2节点的邻接顶点是13,由于我们是DFS,它就会一条路走下去,所以先走左边,即到达1号节点
  2. 然后1号节点的邻接顶点是4,所以接下来箭头指向44是一个出度为0的节点,它没有邻接顶点,所以不用再往下递归,把4直接保存到栈中。
  3. 接着返回到1节点,此时1节点没有未访问的临界点,把1压入栈中
  4. 然后返回到2节点,接着走右边这条路,到达3号节点,接着从3号节点的邻接顶点出发,但是都已经访问过了,所以返回3后,直接把3压入栈中,最后返回2,把2压入栈中。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10005;
stack<int> stk;
struct edge{
    int to, nx;
}e[maxn];
int n, m, len, cycle, head[maxn], rd[maxn], vis[maxn];
void insert(int x, int y){//插边
    e[++len].to = y;
    e[len].nx = head[x];
    head[x] = len;
}
void dfs(int u){
    if(cycle) return;//已经存在环
    vis[u] = -1;//标记当前点为起点
    for(int i=head[u]; i; i=e[i].nx){//遍历邻接点
        int v = e[i].to;
        if(!vis[v]) dfs(v);
        else if(vis[v] == -1){//如果回到了起点,说明存在环
            printf("Cycle
");
            cycle=1;
            return;
        }
    }
    vis[u] = 1;
    stk.push(u);
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1; i<=m; i++){
        int x, y; scanf("%d%d", &x, &y);
        insert(x ,y);
        rd[y] ++;
    }
    for(int i=1; i<=n; i++) if(!rd[i]) dfs(i);//如果入度为0,开始dfs
    if(!cycle)//无环
        while(!stk.empty()){
            printf("%d ", stk.top());
            stk.pop();
        }
    return 0;
}
原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12780954.html