图的拓扑排序

定义:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

来自https://baike.baidu.com/item/%E6%8B%93%E6%89%91%E6%8E%92%E5%BA%8F/5223807?fr=aladdin

基本思路:

如果一个点只有出度,很明显只能在第一位,同如果一个点只有入度只能放在觉后面。

于是,我们可以先输出无入度的点,然后在这个DAG中就可以忽略这些已经输出的点,接下来就是删掉这些点所连的所有边。再重复此操作,直到图为空(或者没有入度为零的点,此时说明此图不存在拓扑排序)就得到了我们要的序列。

基本实现:

类似于bfs

用一个数组In用来保存入度,先将入度为0的入队,然后一个一个弹出里面的点,进行下列操作

       删掉这个点,将其所连的点的入度减一(这里可以看出用邻接表或者链式前向星好一些),当遇到入度为0的将其入队。

最后判断是否有点没有入队,如果有则说明不存在拓扑排序,否则按队列弹出(入队)顺序输出就可以得到一个正确的序列

 

上面的算法只能求一种拓扑排序,如果要求所有的序列,用dfs按同样的思路进行搜索就行

模板题:http://acm.hdu.edu.cn/showproblem.php?pid=1285

题意很明确

思路:需要求得是字典序最小的一个序列,一般情况下我们是按入队顺序排列,现在我们要小的在前面,很容易想到用优先级队列处理

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<set>
#include<vector>
#define maxn 505

using namespace std;

int n, m;
int Que[maxn];
int in[maxn];
vector<vector<int>> Map(maxn);
priority_queue<int, vector<int>, greater<int>> PQ;

void bfs()
{
    int End = 1;
    for(int i = 1; i <= n; i++)
    {
        if(!in[i])
        {
               PQ.push(i);
        }
    }

    while(!PQ.empty())
    {
       Que[End] = PQ.top();PQ.pop();
        int node = Que[End++];
        for(auto x : Map[node])
        {
            in[x]--;
            if(!in[x])
            {
                PQ.push(x);
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d%c", Que[i], i == n ? '\n' : ' ');
    }
}
int main()
{
   while(cin >> n >> m)
   {
         for(int i = 1; i <= n; i++)
        {
            Map[i].clear();
        }
       memset(in, 0, sizeof(in));
       for(int i = 0; i < m; i++)
       {
           int u, v;
           cin >> u >> v;
           Map[u].push_back(v);
           in[v]++;
       }
       bfs();
   }
   return 0;
}

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值