有向图的拓扑序列

不必太过在意标题,拓扑排序只不过是排序的一种:每个节点都向后指向进而形成的结构,即对于图中的每条边 (x,y),x 都出现在 y 之前。

拓扑序列

一定是针对有向图来说的,无向图没有这一说法。
如果一个图形成了闭环,那么一定不是拓扑图。那么有向无环图一定存在一组拓扑序列。
度数:入度、出度。
入度:是指有多少节点形成的边指向该节点。出度:是指该节点有多少条边指向其他节点。
那么任意一个入度为0的点都可以作为起点。

对于这样一个有向图来说:1的入度为0,出度为2。2的入度为1,出度为1。3的入度为2,出度为0。

那么1就可以作为起点。

题目:

848. 有向图的拓扑序列 - AcWing题库

思路(伪代码)

入度为0的点入队,如果有环的话,那么这个环上一定没有入度为0的点
//宽搜
while(队列不空)
{
    int t=q.front();
    //枚举t的所有出边t→j
    //删掉t→j这条边(因为t为队头即在最前面,所以t→j这条边一定满足拓扑序列)
    //这时候j的入度会减少,所以让j的入度减去1
    if(j的入度为0)
    {
        那么j就可以作为队头了。
        //j入队
        q.push(j);
    }
}

代码:

数组模拟:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=1e5+10;

int h[N],e[N],ne[N],idx;
int n,m;
int d[N],q[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

bool topo()
{
    int hh=0,tt=0;
    //数值是:1~n
    for(int i=1;i<=n;i++)
    {
        if(!d[i])
           q[tt++]=i;//队列记录度数为0的节点的索引
    }
    
    while(hh<=tt)
    {
        int t=q[hh++];//取出头节点的索引
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];//t指向j形成的一条边
            d[j]--;//j的入度会少1
            if(!d[j])
            {
                q[tt++]=j;//入队
            }
        }
    }
    //如果是一个拓扑顺序的话
    return tt==n;
}

int main()
{
    cin >> n >> m;
    memset(h,-1,sizeof h);
    //m次询问
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin >> a >> b;
        add(a,b);
        //a指向b,所以b的入度数+1
        d[b]++;
    }
    
    if(topo())
    {
        //入队的顺序即为拓扑的顺序
        for(int i=0;i<n;i++) cout << q[i] << " ";
    }
    else cout << "-1";
    return 0;
}

队列:

~~慢慢的这种题连暴力都不会写了~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值