拓扑排序【入门】

版权声明:转载什么的好说,附上友链就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不相等,就说明无拓扑序列

猜你喜欢

转载自blog.csdn.net/sodacoco/article/details/86586881