c++图论——基础拓扑排序

目录

一,拓扑排序简介

二,拓扑排序算法

1)普通拓扑排序算法普通拓扑排序算法)

2)拓扑和动态规划的结合

三,例题

蓝桥杯官网------走多远

题目描述

输入描述

输出描述

输入输出样例

[示例 1](#示例 1)

代码详解:

注:本文所有题目均来自蓝桥杯官网公开真题,仅做算法学习,代码皆由本人做出来并附上解析!

一,拓扑排序简介

拓扑排序是一种针对 "有向无环图" 的算法,用于解决一些有 "依赖关系" 的问题。拓扑序保证了当处理到某个点时,其所有的入点都已经处理过了。

例如下面这个图(来自蓝桥杯官网),拓扑序可以保证:处理点 2 之前,点 4 和点 6 都处理过。处理点 3 之前,点 2 和点 6 都处理过。

拓扑排序不一定是 "唯一" 的,只要满足拓扑关系即可。以下是一些下图(来自蓝桥杯官网)的可能拓扑序:

1, 4, 6, 2, 5, 7, 3\]\[7, 1, 4, 6, 2, 3, 5\]\[7, 1, 6, 4, 2, 5, 3\]...我们可以发现每个点的左侧包含它的所有入点。 ![](https://i-blog.csdnimg.cn/direct/d6ad281742bf41809f836f86fbd31ae5.png) ## 二,拓扑排序算法 ### 1)普通拓扑排序算法 拓扑排序一般借助 queue(队列),使用类似 BFS 实现。先处理出每个点的入度,这个在读入边的时候处理。图一般用邻接表建立。拓扑排序一般借助 queue(队列),使用类似 BFS 实现。先处理出每个点的入度,这个在读入边的时候处理。图一般用邻接表建立。 代码: ```cpp void topo() { queue q; //将所有入度为0的点加入队列 for (int i = 1; i <= n; ++i)if (!ind[i])q.push(i); while (q.size()) { //取出队头的点x,此时它的入度一定为0,因为x是第一个进入队列的入度为0的点 int x = q.front(); q.pop(); for (const auto& y : g[x]) { //处理边x->y ind[y]--;//处理完成后y入度-- if (!ind[y])q.push(y);//如果y入度为0,说明y的所有入点已经处理完成了,直接入队 } } } ``` 在main函数中,新增一条边: ```cpp vectorg[N]; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; g[u].push_back(v);//添加u------->v有向边 ind[v]++;//v的入度+1 } return 0; } ``` ### 2)拓扑和动态规划的结合 在枚举边 x-\>y 的时候,可以进行状态转移,于是可以和动态规划结合起来。这样的 DP 也叫做 DAG-DP(有向无环图上的动态规划)。状态转移一般只发生在枚举所有边的时候。 代码: ```cpp void topo() { queue q; //将所有入度为0的点加入队列 for(int i = 1;i <= n; ++ i)if(!ind[i])q.push(i); while(q.size()) { //取出队头的点x,此时它的入度一定为0 int x = q.front();q.pop(); for(const auto &y : g[x]) { //处理边x->y //在这里进行状态转移 //dp[y] = ...dp[x]... ind[y] --;//处理完成后y入度-- if(!ind[y])q.push(y);//如果y入度为0,说明y的所有入点已经处理完成了,直接入队 } } } ``` ## 三,例题 ### 蓝桥杯官网------走多远 #### 题目描述 给定一个 n 个点,mm 条边的有向无环图,从入度为 0 点出发,顺着边最远能走多远,若不存在这样的点,输出 0。 #### 输入描述 第一行输入一个 n,m​​ 。 接下来 m 行,每行输入俩个整数 u,v 代表有一条有向边从 u 到 v​. 1≤n,m≤10\^6,1≤u,v≤n​ #### 输出描述 输出一个整数表示最长距离。 #### 输入输出样例 ##### 示例 1 输入: 2 1 1 2 输出: 1 解析:设状态 dp \[i\] 表示 i 点距离某一个起点的最远距离,状态转移的方向就是拓扑的顺序。假如存在一条边 x-\>y,则有dp \[y\]=max (dp \[y\], dp \[x\] + 1);初始时 dp \[i\]=0; #### 代码详解: ```cpp #include #include #include using namespace std; using ll=long long; const int N=1e6+9; int n,m,dp[N],ind[N];//入度 vectorg[N]; void topo() { queueq; //走入度为0的点(找所有起点) for(int i=1;i<=n;i++) { if(!ind[i]) q.push(i); } //只要队列不为空,就不断拓展 while(q.size())//或者写while(!q.empty()) { //取出队头元素,并pop掉(很重要) int x=q.front();q.pop(); //枚举所有边 for(const auto &y:g[x]) { dp[y]=max(dp[y],dp[x]+1); if(--ind[y]==0)q.push(y);//从x往下走,只走入度为0的,那么每次走下一步,由于上一步已经删除 //则下一步的入度就要减1,此时若下一步入度为0就走,并且入队 } } } void solve() { cin>>n>>m; for(int i=1;i<=m;i++) { int x,y;cin>>x>>y; ind[y]++;//入度增加 g[x].push_back(y); } topo();//拓扑排序 int ans=0; for(int i=1;i<=n;i++)ans=max(ans,dp[i]); cout<

相关推荐
_OP_CHEN3 小时前
【算法基础篇】(三十六)图论基础之拓扑排序:从原理到实战,搞定 DAG 图的 “先后次序” 难题
c++·算法·蓝桥杯·图论·拓扑排序·算法竞赛·acm/icpc
xie_pin_an2 天前
深入浅出 C 语言数据结构:从线性表到二叉树的实战指南
c语言·数据结构·图论
Maỿbe2 天前
力扣hot图论部分
算法·leetcode·图论
Bruce_kaizy2 天前
c++图论————图的基本与遍历
c++·算法·图论
_OP_CHEN2 天前
【算法基础篇】(三十五)图论基础之最小生成树:从原理到实战,彻底吃透 Prim 与 Kruskal 算法
算法·蓝桥杯·图论·最小生成树·kruskal算法·prim算法·acm/icpc
浔川python社2 天前
C++小程序编写系列(2)
c++·算法·图论
qq_418247883 天前
恒源云/autodl与pycharm远程连接
ide·人工智能·python·神经网络·机器学习·pycharm·图论
m0_639397293 天前
代码随想录算法训练营第五十天|图论理论基础,深搜理论基础,98. 所有可达路径,广搜理论基础
算法·图论
做怪小疯子4 天前
LeetCode 热题 100——图论——岛屿数量&腐烂的橘子&课程表
算法·leetcode·图论