问题:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。(如下图)
思想:
1.找到一个没有子节点的节点,他就是最后一个要做的事情。
2.删除这个子节点。
3.在当前图里再次寻找没有子节点的节点。
4.删除到没有节点时,将删除顺序倒过来就是拓扑排序的顺序。
补:如果已经找不到没有子节点的节点,说明这张图有环,不存在拓扑排序。
如下图:
有五件事情要做,(x,y)表示做y之前必须做过x。现在五件事之间的关系为(1,2)(1,5)(5,4)(4,3)(3,2)(5,2)
1,找到没有出度的节点,就是节点2
2.删除这个节点并删除有关的边,并记录2是要最后一件做的事情。
3.重复上述操作的到结果:一次删除的点为2 3 4 5 1则该图的拓扑排序为1 5 4 3 2
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <vector> using namespace std; const int maxn=1e3+10; int G[maxn][maxn]; int n; int c[maxn]; int topo[maxn],t; bool dfs(int u){ c[u]=-1; //c[u]==-1表示正在查找这个点的子节点 for(int v=0;v<n;v++)if(G[u][v]){ if(c[v]<0)return false; //因为G[u][v]!=0才会进入这里,代表v时u的子节点。 //c[v]==-1,代表正在查找v的子节点,说明u时v的子节点 //说明u和v之间是一个环 else if(!c[v]&&!dfs(v))return false; /*这句话理解为 if(!c[v]){ //如果点v没有查找过,那么查找点v的子节点 if(!dfs(v)){ //如果v的子节点内存在环,返回false return false; } } */ } c[u]=1;topo[--t]=u;//没有子节点的节点会最先到达这里 return true; } bool toposort(){ t=n; memset(c,0,sizeof(c)); for(int u=0;u<n;u++) if(!c[u]) if(!dfs(u)) return false; return true; } int main() { int m; memset(G,0,sizeof(G)); scanf("%d%d",&n,&m); for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); G[a][b]=1; } if(toposort()) for(int i=0;i<n;i++){ printf("%d ",topo[i]); } else printf(".....\n"); return 0; }