【算法学习笔记】19:拓扑排序

2023-11-14

1 简述

计算拓扑序列的一个方式是,用BFS来尝试访问所有的节点,但是有一个约束就是只有入度为 0 0 0的节点才能被加入到扩展队列里。每次从队列里取出一个节点,也就同时在图中将这个节点拆除,所以它的所有后继的节点都减少 1 1 1,如果已经减少到 0 0 0,那么就可以加入到队列中。

在这里插入图片描述

在上面的例子中,一开始只有 a a a的入度是 0 0 0,所以先把 a a a加入到队列中,队列中:
a a a

然后取出队头 a a a并在图中拆除,然后它的后继 c c c的入度变成 1 1 1 b b b的入度变成 0 0 0,把 b b b加入到队列里,队列中:
b b b

然后取出队头 b b b并在图中拆除,然后它的后继 c c c d d d的入度都变成 0 0 0,都加入到队列里,队列中是:
c   d c~d c d

或者
d   c d~c d c

接下来也是重复这个过程,最后得到拓扑序列是 a   b   c   d a~b~c~d a b c d或者 a   b   d   c a~b~d~c a b d c(取决于 c c c d d d哪个先从“ d d d的所有后继”这个集合中访问)。

2 模板题:有向图的拓扑序列

在实现拓扑排序时,用模拟队列来代替STL的队列比较方便。一方面是,观察上面的过程可以发现,只要所有节点都被加入到队列里了,那么就能说明所有的节点都能被访问,就说明存在拓扑序列。如果用模拟队列,由于它的两个指针一直往后移的特性,只要看一下队尾指针tt是不是在n-1位置就能知道是不是这n个元素都加入过队列中了。

另外,由于模拟队列删除元素只是做++hh的操作,而没有破坏队头hh位置的元素取值,所以最后输出拓扑序列的时候可以直接从0n-1遍历一下队列,输出的就是拓扑序了。

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;

int n, m;

// 记录每个节点的入度
int d[N];

// 邻接表
int h[N], e[N], ne[N], idx;

// 邻接表添加有向边
void add_edge(int a, int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++ ;
}

// 模拟队列
int q[N], hh, tt = -1;

// 拓扑排序,如果存在拓扑序返回真
bool topo_sort() {
    // 先将所有入度为0的节点入队
    for (int i = 1; i <= n; i ++ ) {
        if (!d[i])
            q[ ++ tt] = i;
    }
    // BFS访问过程
    while (hh <= tt) {
        // 取队头节点t
        int t = q[hh ++ ];
        // 删除节点t,所以将节点t的所有后继j的入度-1
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = e[i];
            d[j] -- ;
            // 如果已经减少到0了,就加到队列里
            if (!d[j]) q[ ++ tt] = j;
        }
    }
    // 如果所有n个节点都加入过队列,就存在拓扑序
    return tt == n - 1;
}

int main() {
    // 初始化邻接表
    memset(h, -1, sizeof h);
    // 读取m条有向边,同时维护节点的入度
    cin >> n >> m;
    for (int i = 0; i < m; i ++ ) {
        int a, b;
        cin >> a >> b;
        add_edge(a, b);
        d[b] ++ ;
    }
    // 如果存在拓扑序,模拟队列中依次入队的顺序就是拓扑序
    if (topo_sort()) {
        for (int i = 0; i < n; i ++ )
            cout << q[i] << ' ';
        cout << endl;
    }
    else {
        cout << -1 << endl;
    }
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法学习笔记】19:拓扑排序 的相关文章

  • 2022 RoboCom 世界机器人开发者大赛-本科组(省赛)-RC-u5 树与二分图

    2022 RoboCom 世界机器人开发者大赛 本科组 省赛 RC u5 树与二分图 文章目录 2022 RoboCom 世界机器人开发者大赛 本科组 省赛 RC u5 树与二分图 题目描述 输入格式 输出格式 输入样例 输出样例 思路 A
  • lambda

    外部变量访问方式说明符 不捕获任何变量 以引用方式捕获所有变量 用值的方式捕获所有变量 可能被编译器优化为const foo 以引用捕获foo 但其余变量都靠值捕获 foo 以值捕获foo 但其余变量都靠引用捕获 bar 以值方式捕获bar
  • P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib【普及】

    USACO1 5 特殊的质数肋骨 Superprime Rib 题目描述 农民约翰的母牛总是产生最好的肋骨 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们 农民约翰确定他卖给买方的是真正的质数肋骨 是因为从右边开始切下肋骨 每次
  • Codeforces-1454E Number of Simple Paths(基环树-思维)

    题目大意 给你n个点 n条边 求图中简单路径的个数 题目思路 n个点n条边 那么图中一定有一个环 拿这个图来讲 我们将两点间的关系分为4种 1 两点都在环上 简单路径的个数为2 例如2与5 2 一个点在环上一个点不在环上 简单路径个数为2
  • A*算法 解决(有环图)第k短路径长度(C++)

    算法竞赛 file author jUicE g2R qq 3406291309 彬 bin 必应 一个某双流一大学通信与信息专业大二在读 brief 一直在算法竞赛学习的路上 copyright 2023 9 COPYRIGHT 原创技术
  • Financial Crisis【点双连通分量】

    题目链接 HDU 3749 你以为学了Tarjan会写几个边双就真的理解什么是双连通分量了吗 我原来真的不懂什么叫做点双BCC 不过这都没有关系 解决了这个问题之后 我终于知道了什么叫做点双连通分量了 这是一个绝对绝对经典的问题 首先讲一下
  • Even Degree【2020 年 “游族杯”E题】【欧拉回路】

    题目链接 题意 有N个点 M条边 每次可以删去一条两端点的度不都是奇数的边 问最多可以删除几条边 题目保证初始所有点度为偶数 首先 题目保证了初始的时候所有的点的度都是为偶数的 于是原图中的每一个联通块一定是一个欧拉回路 对于欧拉回路 最好
  • The Stable Marriage Problem 【HDU - 1914】【稳定婚姻匹配问题】

    题目链接 Problem Description The stable marriage problem consists of matching members of two different sets according to the
  • POJ 3259 Wormholes(最短路——Bellman-ford)

    A Wormholes While exploring his many farms Farmer John has discovered a number of amazing wormholes A wormhole is very p
  • 《算法图解》读书笔记(二)

    第六章 图 广度优先搜索 1 解决最短路径问题 shortest path problem 的算法被称为广度优先搜索 breadth first search 2 图由节点 node 和边 edge 组成 一个节点可能与众多节点直接相连 这
  • Fix a Tree【Codeforces 699 D】【dfs + 树的性质】

    Codeforces Round 363 Div 2 D 题意 有N个点 每个点i都有一个父节点p i 如果 i p i 则是说明i结点是根结点 现在我们给出这样的1 N的p i 这可能是不合法的 问 我们应该最少改变多少个使它变成一棵合法
  • 【算法笔记】Prim算法

    定义 prim算法 图论中的一种算法 可在加权连通图里搜索最小生成树 由此算法搜索到的边子集所构成的树中 不但包括了连通图里的所有顶点 并且其所有边的权值之和最小 算法描述 输入 一个加权连通图 其中顶点集合为V 边集合为E 初始化 Vne
  • 2023杭电暑假多校4 题解

    3 Simple Set Problem 题意 k 个多重集合 每个集合选出一个数形成新集合A 求 m a x A m
  • 数据结构算法—邻接表存储的无向图求连通分量个数

    数据结构算法 邻接表存储的无向图求连通分量个数 邻接表存储结构 typedef struct ArcNode int adjvex 边指向的顶点 struct ArcNode nextarc 下一条边的指针 ArcNode typedef
  • Dinic算法学至大佬,学以致用【挂上相应的题目】

    这个巨佬讲的超级厉害 学起来很快 还有优化的说呢 Dinic算法 研究总结 网络流 网络流是信息学竞赛中的常见类型 笔者刚学习了最大流Dinic算法 简单记录一下 网络流基本概念 什么是网络流 在一个有向图上选择一个源点 一个汇点 每一条边
  • 1600*B. pSort(并查集)

    解析 并查集 将能够交换的位置相连 查看对应的位置能够交换 include
  • MOOC PTA 08-图8 How Long Does It Take

    http pta patest cn pta test 18 exam 4 question 631 构建图的邻接矩阵 寻找入度为0的顶点 将其压入队列 出队列时对其相连接的顶点入度减1 更新每个顶点的最大时间 刚开始提交 3和5 测试点过
  • 图 - Java实现无向带权图的邻接矩阵表示法

    图 Java实现无向带权图的邻接矩阵表示法 1 图 1 1 图的介绍 图 Graph 是一种复杂的非线性表结构 图中的元素我们就叫做顶点 vertex 图中的一个顶点可以与任意其他顶点建立连接关系 我们把这种建立的关系叫做边 edge 跟顶
  • Binary Tree on Plane【费用流】

    题目链接 CF 277 E 题意翻译 给你平面上 n 个点 2 n 400 要求用这些点组成一个二叉树 每个节点的儿子节点不超过两个 定义每条边的权值为两个点之间的欧几里得距离 求一个权值和最小的二叉树 并输出这个权值 其中 点 i 可以成
  • 860.染色法判定二分图

    二分图是指一个图中的所有顶点可以分为两部分 并且每条边连接的是属于不同部分的两个顶点 include

随机推荐

  • mysql数据库入门教程

    Markdown database notebook Markdown database notebook 1 1 Mysql知识 基础 1 1 1 Msyql的基本知识 1 2 Mysql知识 深入 1 2 1 Mysql的储存引擎 1
  • DIV与Table布局在大型网站的可用性比较

    DIV与TABLE本身并不存在什么优缺点 所谓web标准只是推荐的是正确的使用标签 好比说 DIV用于布局 而TABLE则本来就是转二维数据的 让TABLE做该做的事 并不是说页面里不出现TABLE就是多么多么牛 用DIV进行排版的优势就是
  • jQuery-migrate 插件---各类版本下载

    步骤 1 CDN jquery migrate 2 找到所需版本打开 3 全选复制到自己创建的记事本 4 复制 5 粘贴到IntelliJ IDEA 模块下的 webapp js 没有自己手动创建目录 jquery migrate 1 4
  • Oracal的Lpad函数

    lpad函数是Oracle数据库函数 lpad函数从左边对字符串使用指定的字符进行填充 从其字面意思也可以理解 l是left的简写 pad是填充的意思 所以lpad就是从左边填充的意思 语法格式如下 lpad string padded l
  • unity笔记-20161109

    1 Animator CullingMode 动画器剔除模式 AlwaysAnimate Always animate the entire character Object is animated even when offscreen
  • 在Python中如何优雅地处理PDF文件

    1 引言 PDF文档是我们在日常工作中经常会遇到的文件格式 有时我们需要编辑并从中提取一些有用的数据 在本文中 我将向大家介绍如何使用Python中的PDF库从PDF文档中提取文本 表格和图像以及其他类型的数据 闲话少说 我们直接开始吧 2
  • JS实现请假时长计算(计算小时数差)

    给公司做了一套系统 涉及到请假单功能开发 在计算请假时长这块总结一下 按天计算的就不总结了比较简单 这里总结一下按小时数计算的 话不多说 直接上代码 获取两个日期相差的工作小时 不包括节假日 function getHour StartTi
  • Python 中的异常种类

    常用异常 AttributeError 试图访问一个对象没有的树形 比如foo x 但是foo没有属性x IOError 输入 输出异常 基本上是无法打开文件 ImportError 无法引入模块或包 基本上是路径问题或名称错误 Inden
  • Matlab quiver函数用法 - 画矢量箭头图

    提要 quiver x y u v 在点 x y 处画 u v 所定义的向量箭头 x y u v必须是维度和元素数都一样的矩阵 如果是一维数组的话 x y u v的元素数必须一致 quiver函数会自动调整箭头的长度以适应显示 quiver
  • iOS静态方式绕过svc反动态调试

    在iOS反动态调试中 常用到 svc 0x80 通过svc汇编实现对ptrace syscall的调用 实现反动态调试 使得lldb无法附加到app进程 不易定位到代码位置 增加反调试绕过难度 如何绕过这种反调试手段呢 本文通过搜索app的
  • ajax请求发送成功,后端没有响应

    前端请求状态200 但是后端无反应结果是以为我的登录拦截器把这个请求拦截了 登录之后就发现后端有响应了 2021 4 1日常错误
  • Python自学笔记2-语法

    这里介绍Python的基本语法和编程风格 Python的保留字 如下表 不能以这些名字给函数或变量命名 and exec not assert finally or break for pass class from print conti
  • UE5 C++插件开发指南目录

    这一篇原本的标题是 如何将插件上架到UE虚幻商城 但是Up主聆枫LingFeng已经分享了相关议题 而且非常详细 UE 虚幻商城上架指南 所以这一篇就改写目录了 其实由谁来讲并不重要 重要的是讲的内容是否是读者需要的 希望大家可以从中受益
  • SQL练习(less-5\8)延时注入

    本文为学习笔记 仅限学习交流 不得利用 从事危害国家或人民安全 荣誉和利益等活动 SQL注入 字符型 延时注入 延时型语句 sleep 参数 任意正整数 一般为秒 If a b c 它的意思就是如果条件A成立 则输出结果B 否则输出结果C
  • HTML 好看界面

    无聊逛外网的时候 突然看见一个用HTML写的界面 我觉得挺好看 对于我这个才接触这个的学生来说 挺厉害的 所以我也把他分享出来 你们可以去参考参考
  • 第50讲:Scrapy 部署不用愁,Scrapyd 的原理和使用

    上节课我们的分布式爬虫部署完成并可以成功运行了 但是有个环节非常烦琐 那就是代码部署 我们设想下面的几个场景 如果采用上传文件的方式部署代码 我们首先需要将代码压缩 然后采用 SFTP 或 FTP 的方式将文件上传到服务器 之后再连接服务器
  • linux磁盘分区以及配置文件设置

    硬盘分区有三种 主磁盘分区 83 扩展磁盘分区 5 逻辑分区 包括swap交换分区82 一个硬盘主分区至少有1个 最多4个 扩展分区可以没有 最多1个 且主分区 扩展分区总共不能超过4个 逻辑分区可以有若干个 交换分区必须存在但一般不用 补
  • hdu 6121 Build a tree

    Problem acm hdu edu cn showproblem php pid 6121 Meaning 一棵 n 个点的完全 k 叉树 结点标号从 0 到 n 1 求以每一棵子树的大小的异或和 Analysis 一层层地统计答案 找
  • LED 数码管共阴共阳的区别+静态/动态显示

    51单片机 数码管动态显示 1 共阴共阳定义 LED 共阴极指的是LED共同的接点是GND 接地 而共阳极指的是LED共同的接点是电源 LED亮灯的条件是两端有电势差 最后一段h dp小数点在高位 第一段a在低位 hgfedcba xxxx
  • 【算法学习笔记】19:拓扑排序

    1 简述 计算拓扑序列的一个方式是 用BFS来尝试访问所有的节点 但是有一个约束就是只有入度为 0 0 0的节点才能被加入到扩展队列里 每次从队列里取出一个节点 也就同时在图中将这个节点拆除 所以它的所有后继的节点都减少 1 1 1 如果已