版权声明:转载什么的好说,附上友链就ojek了,同为咸鱼,一起学习。 https://blog.csdn.net/sodacoco/article/details/86586881
参看资料:
https://blog.csdn.net/lisonglisonglisong/article/details/45543451
https://blog.csdn.net/qq_41713256/article/details/80805338
什么是拓扑排序:
在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
1》每个顶点出现且只出现一次。
2》若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
PS:有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。
对图进行拓扑排序:
在一个有向图中,对所有的节点进行 排序,要求:没有一个节点指向它前面的节点。
1》先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
2》一直做改操作,直到所有的节点都被分离出来。
3》如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
例:
实现代码:
1》效率较低,但易于理解:
//b[]为每个点的入度
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(b[j]==0){ //找到一个入度为0的点
ans=j; //标记该点
vis[cnt++]=j;//将该点放入目标序列
b[j]--; //将该点入度改为-1,表示该点不存在
break;
}
}
for(j=1;j<=n;j++)
if(a[ans][j]) b[j]--; //与入度为0的点ans相连的点的入度减一
}
printf("%d",vis[0]);
for(i=1;i<cnt;i++) printf(" %d",vis[i]); //输出目标序列
printf("\n");
2》效率较高,也挺好理解【看注释老弟】:
queue<int>q;
for(int i=0;i<n;i++) //n 节点的总数
if(in[i]==0) q.push(i); //将入度为0的点入队列
vector<int>ans; //ans 为拓扑序列
while(!q.empty()){
int p=q.top();
q.pop(); // 选一个入度为0的点,出队列
ans.push_back(p); //将该度数为零的点放入目标队列
for(int i=0;i<edge[p].size();i++){ //枚举与该度数为0的点想连的节点
int y=edge[p][i];
in[y]--; //入度减1
if(in[y]==0) //若得到一个入度为0的点,将其放入度数为0的队列
q.push(y);
}
}
if(ans.size()==n){ //所有的点都进入了拓扑序列
for(int i=0;i<ans.size();i++)
printf( "%d ",ans[i] );
printf("\n");
}
else printf("No Answer!\n"); // ans 中的长度与n不相等,就说明无拓扑序列