拓扑排序

拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

一个有向图无法拓扑排序时只有一种情况:该有向图中存在环.刘汝佳入门经典P111中给出了拓扑排序的代码,其中关键点在于状态数组C[i]的使用.代码如下,具体细节自己体会:

/*刘汝佳 入门经典P110
有向图拓扑排序,输入数据为:
5 4
0 1
1 2
2 3
4 3
输出为:4 0 1 2 3
4 4
0 1
1 2
2 3
3 0
输出为:存在有向环,无法拓扑排序
*/

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100+5;
int G[maxn][maxn];//有向图
int n,m;//n为点数,m为边数
int c[maxn];//为-1,0,1 分别表示当前点的3中状态:正在被访问,未被访问,已访问完
int topo[maxn];//拓扑排序的结果,正序存放
int t;//用于计数topo结果当前位置
bool dfs(int u)
{
    c[u]=-1;
    for(int v=0;v<n;v++)if(G[u][v])
    {
        if(c[v]<0) return false;
        if(!c[v]&&!dfs(v)) return false;
    }
    c[u]=1;
    topo[--t]=u;//当u点所指的所有其他节点都拓扑完,就可以把u保存在当前的一个靠前的位置了
    return true;
}

bool toposort()
{
    t=n;
    memset(c,0,sizeof(c));
    for(int i=0;i<n;i++)if(!c[i])//节点从0到n-1编号
        if(!dfs(i)) return false;
    return true;
}

int main()
{
    while(scanf("%d%d",&n,&m)==2&&n&&m)
    {
        memset(G,0,sizeof(G));
        for(int i=0;i<m;i++)
        {
            int u, v;
            scanf("%d%d",&u,&v);
            G[u][v]=1;
        }
        if(!toposort()) printf("存在有向环,无法拓扑排序\n");
        else
        {
            for(int i=0;i<n;i++)
                printf("%d ",topo[i]);
            puts("");
        }
    }
    return 0;
}

如果想要按字典序从小到大输出所有可能的拓扑排序结果,可以看POJ1270题解:

http://blog.csdn.net/u013480600/article/details/30315289

其实判断有向图能否拓扑排序且输出拓扑排序的结果还有另一种非递归的简单方式,该方法更好理解:

http://blog.csdn.net/u013480600/article/details/30516301

注意:如果简化有向图的过程中,出队列的点(即最终入度为0的点)个数<n,说明该图无法简化,也就无法拓扑排序.可见数据结构C语言版(严蔚敏版)

你可能感兴趣的:(ACM)