首页 > 代码库 > 拓扑排序(算法竞赛入门经典)

拓扑排序(算法竞赛入门经典)

拓扑排序的定义:

把每个变量看成一个点,”小于“或者”先后“关系看成有向边,则我们得到一个有向图。这样我们的任务实际上是把一个图的所有节点排序,使每一条有向边的(uv)对应的u都排在v之前,在图论中,我们称之为拓扑排序。不难发现,如果一个有向图里存在回路,则不存在拓扑排序(如果设置一个标志数组,我们可以发现回路中的点一直处于正在被访问状态,这可以作为拓扑排序的结束条件)。

我们先看一个样例:

 

下面我们用邻接矩阵存储这张图:

 

0

1

2

3

0

0

1

1

1

1

0

0

1

1

2

0

0

0

1

3

0

0

0

0

下面我们看看程序输出的结果:

可见我们输出的路径只是很多情况中的一种。

下面附上ac代码:

 1 #include<iostream> 2 #include<string.h> 3 using namespace std; 4 #define maxn 1000 5 int g[maxn][maxn],c[maxn],n,m,t; 6 bool dfs(int u) 7 { 8     c[u]=-1; 9     for(int v=0;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;//访问完毕,标记为已经被访问16     c[--t]=u;//把该节点入栈(此时t!=n,因为已经在递归调用的过程中使t减小了)17     return true;18 }19 bool toposort()20 {21    t=n;22    memset(c,0,sizeof(c));23     for(int v=0;v<n;v++)24     if(!c[v])25     if(!dfs(v)) return false;//存在回路,不能进行拓扑排序26     return true;27 }28 int main()29 {30     cin>>n>>m;31     int u,v;32     memset(g,0,sizeof(g));33     for(int i=1;i<=m;i++)34     {35         cin>>u>>v;36         g[u][v]=1;//读入数据,即输入路径37     }38     if(toposort())//不存在回路,输出路径,这里只是很多路径的一种39     {40         cout<<"一条可能的路径为:"<<endl;41         for(int i=0;i<n;i++)42         cout<<c[i]<<endl;43     }44     else cout<<"no"<<endl;45     return 0;46 47 }