图论:拓扑排序
把一个图的所有节点进行排序,是的每一条有向边(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 }
拓扑排序是后续很多知识点的一个前置技能,一定要深刻掌握