第三章 搜索与图论 拓扑排序

本文介绍了拓扑排序的概念,它是对有向无环图的顶点进行排序的一种方法,使得路径方向得到满足。卡恩算法是实现拓扑排序的主要方式,通过找到入度为零的节点并移除相关边来逐步构建排序序列。当图中存在自环或重边时,拓扑排序仍然有效。文章还提供了一个C++代码示例,展示了如何对给定的有向图进行拓扑排序。在给定的输入样例中,成功输出了合法的拓扑序列123。
摘要由CSDN通过智能技术生成

1、算法思路

拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从u到v的一条路径的话,那么在排序中,v一定出现在u的后面。最接近生活的一个例子就是我们修的课程。
在这里插入图片描述
图片来源
我们一定是先修完一门基础课,再去修进阶课程。
显然如果图中含有圈,那么拓扑排序一定是不可能的。

在实现上我们采用卡恩算法进行实现:
卡恩于1962年提出了该算法。简单来说,假设L是存放结果的列表,先找到那些入度为零的节点,把这些节点放到L中,因为这些节点没有任何的父节点。然后把与这些节点相连的边从图中去掉,再寻找图中的入度为零的节点。对于新找到的这些入度为零的节点来说,他们的父节点已经都在L中了,所以也可以放入L。重复上述操作,直到找不到入度为零的节点。如果此时L中的元素个数和节点总数相同,说明排序完成;如果L中的元素个数和节点总数不同,说明原图中存在环,无法进行拓扑排序。

L ← 包含已排序的元素的列表,目前为空
S ← 入度为零的节点的集合
当 S 非空时:
    将节点n从S移走
    将n加到L尾部
    选出任意起点为n的边e = (n,m),移除e。如m没有其它入边,则将m加入S。
    重复上一步。
如图中有剩余的边则:
    return error   (图中至少有一个环)
否则: 
    return L   (L为图的拓扑排序)

信息来源

2、例题

1.有向图的拓扑排序

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式
第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。

输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 −1。

数据范围
1≤n,m≤10^5
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;

int e[N],ne[N],idx,h[N];
int q[N],tt, hh;
int d[N];

void ins(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}
int main()
{
    int n,m;
    cin >> n >> m;
    memset(h,-1,sizeof h);
    for(int i = 0; i < m; i ++)
    {
        int a,b;
        cin >> a >> b;
        ins(a,b);
        d[b] ++;
    }
    hh = 0,tt = -1;
    for(int i = 1; i <= n; i ++)
    {
        if(d[i] == 0)
        {
            q[++ tt] = i;
        }
    }
    while(tt >= hh)
    {
        int t = q[hh];
        hh ++;
        for(int i = h[t]; i != -1; i = ne[i])
        {
            if(-- d[e[i]] == 0)
            {
                q[++ tt] = e[i];
            }
        }
        if(tt == n - 1)
        {
            for(int i = 0; i < n; i ++)
            {
                cout << q[i] << ' ';
            }
            return 0;
        }
    }
    cout << "-1";
}

实现的思路基本上是按照上面的卡恩算法进行的,对于题目中的重边,这对拓扑排序的结果没有影响,而对于包含自环的图,他也不会有拓扑排序。

参考资料

  1. https://www.jianshu.com/p/0b92b442dca7
  2. 数据结构与算法分析C语言描述(第二版) 9.2
  3. Acwing
  4. 维基百科 拓扑排序词条
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值