使用拓扑排序判断图是否为有向无环图(DAG)

把一个图的所有节点进行排序,是的每一条有向边(u,v)所对应的u都排在v的前面

如果一个有向图的拓扑序列不存在,那么它就不是一个DAG

(DAG的最短路可以用动态规划方法求出,以后再介绍)

好久没有参考刘汝佳的代码了。。

int n,m,t;
int g[maxn][maxn],c[maxn],topo[maxn];

n个点m条边和临时变量t

g是邻接矩阵,对于一个图来说,我们一般是用邻接表来存的,这里直接改成邻接表即可,在邻接表里记录一个每一条边的u节点,这样方便遍历

c数组是用来判断当前点的状态的数组,0表示下标位置及其子孙位置没有进行过拓扑排序,1表示下标位置及其子孙位置进行过拓扑排序,然后-1表示当前节点的访问位于函数调用栈

topo是拓扑序列

bool dfs(int u)
{
    c[u]=-1;
    for(int v=1;v<=n;v++)
    if(g[u][v])
    {
        if(c[v]<0) return false;
        else if(!c[v]) dfs(v);
    }
    c[u]=1;topo[t--]=u;
    return true;
}

函数的意义还是很明显的,明白了c数组的含义不难理解这个函数

bool toposort()
{
    t=n;
    memset(c,0,sizeof(c));
    for(int u=1;u<=n;u++)
    if(!c[u])if(!dfs(u)) return false;
    return true;
}

每个点均调用一次dfs,保证所有点都出现在序列里面

下面给出完整的实现:

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=1005;
 4 int n,m,t;
 5 int g[maxn][maxn],c[maxn],topo[maxn];
 6 bool dfs(int u)
 7 {
 8     c[u]=-1;
 9     for(int v=1;v<=n;v++)
10     if(g[u][v])
11     {
12         if(c[v]<0) return false;
13         else if(!c[v]) dfs(v);
14     }
15     c[u]=1;topo[t--]=u;
16     return true;
17 }
18 bool toposort()
19 {
20     t=n;
21     memset(c,0,sizeof(c));
22     for(int u=1;u<=n;u++)
23     if(!c[u])if(!dfs(u)) return false;
24     return true;
25 }
26 int main()
27 {
28     while(scanf("%d%d",&n,&m)==2&&n)
29     {
30         memset(g,0,sizeof(g));
31         for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);g[u][v]=1;}
32         if(toposort()){for(int i=1;i<=n;i++) printf("%d ",topo[i]);}
33         else printf("No");
34         printf("\n");
35     }
36     return 0;
37 }

拓扑排序是后续很多知识点的一个前置技能,一定要深刻掌握

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9388179.html