拓扑序列是将一个有向无环图的点排序后的序列,排序规则是,对任意一条由v指向u的边都满足在序列中v在u左边,显然,对于一个有向无环图,拓扑序列可能不唯一。
为什么要有向?因为拓扑排序的规则就是方向。
为什么要无环?如果对于u和v两个点在同一个环内,就意味着u可以到v,v可以到u,那么在拓扑序列中,u是在v的左边还是右边呢?
说一下拓扑排序的思路。(看了很多代码都没看懂 只看懂了拓扑序列 下面是我自己写的代码)
读入所有边后先枚举所有的点,然后将没有入边的点入队(显然拓扑序列最左边的点都是没有入边的)然后将队列中所有点及其出边删除,继续枚举没有入过队的入边为0的点入队。反复如此,直到所有点都入过队了,结束循环,然后按照入队顺序输出所有点。
找了好久也没看到拓扑排序什么大的用处,只知道可以判断有向图是否有环或者是否是链(即拓扑序列是否唯一)不管那么多,先把拓扑排序学了,以后做题如果看到了拓扑排序的题就会想起来的。
下面是一个有向无环图的便利过程。
再给个将有向无环图变成序列的图:
上代码:
#include<cstdio>
using namespace std;
int n,m;
int to[5000],next[5000],begin[5000];//链式前向星 不懂的看我博客
int vis[5000],q[5000],leave;//vis[i]是点i的入边数 q是队列 leave是已经入过队的点数
bool p[5000];//p[i]判断点i是否已经入过队
int main(){
int i,j,k,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
to[i]=y;
next[i]=begin[x];
begin[x]=i;
vis[y]++;//y的入边数+1
}//链式前向星
int l=0,f=0;
for(i=1;i<=n;i++){//先将所有无入边的点入队
if(!vis[i]){
f++;
q[f]=i;
p[i]=1;
leave++;
}
}
while(leave<n){
while(l<f){//在队列内所有点出队后再搜索无入边的点 节约时间
l++;
for(i=begin[q[l]];i;i=next[i]){//链式前向星
vis[to[i]]--;//删除点 将这个点所有出边到达的点的入边数-1
}
}
for(i=1;i<=n;i++){//所有点出队后再寻找新的无入边的点
if(!vis[i]&&!p[i]){
f++;
q[f]=i;
p[i]=1;
leave++;
}
}
}
for(i=1;i<=n;i++)printf("%d ",q[i]);
return 0;
}