数据结构与算法学习笔记----拓扑排序
数据结构与算法学习笔记----拓扑排序
@@ author: 明月清了个风
@@ first publish time: 2024.12.10
拓扑排序
拓扑排序是一个有向无环图,需要满足的条件是:若存在一条从顶点 A A A指向顶点 B B B的路径,那么在拓扑序列中 A A A出现在 B B B前面。
BFS用来求拓扑序列很方便,因为BFS强调层级的概念,在图论中,入度和出度是描述有向图顶点的重要属性,而在拓扑序列中,我们就是使用顶点的入度进行BFS的。
对于一个顶点 B B B来说,如果他有入度,那么必有另一个顶点 A A A通过一条边指向它,并且顶点 A A A在拓扑排序中在它之前,那么我们可以将所有入度为 0 0 0的点入队,因为没有任何边指向他们,所以他们可以在拓扑排序中排在前面,然后进行BFS,在BFS的过程中逐步减去每个被遍历到的点的入度,入度为 0 0 0的点继续入队,完成遍历。
至于是否有环的判断,就看最后的拓扑序列中是否所有点都入队了,下面是一道模版题,可以看一下代码的处理。
Acwing 848. 有向图的拓扑序列
[原题链接](848. 有向图的拓扑序列 - AcWing题库)
给定一个 n n n个点 m m m条边的有向图,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 − 1 -1 −1。
若一个由图中所有点构成的序列 A A A满足:对于图中的每条边 ( x , y ) (x ,y) (x,y), x x x在 A A A中都出现在 y y y之前,则称 A A A是该图的一个拓扑序列。
输入格式
第一行包含两个整数 n n n和 m m m。
接下来 m m m行,每行包含两个整数 x x x和 y y y,表示存在一条从 x x x走到 y y y的有向边 ( x , y ) (x, y) (x,y)。
输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。
否则输出 − 1 -1 −1。
数据范围
1 ≤ n , m ≤ 1 0 5 1 \leq n,m \leq 10^5 1≤n,m≤105
代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int d[N]; // 记录每个点的入度,也就是有多少条边指向该点,
int q[N], hh, tt = -1; // 因为最后要输出拓扑排序,用数组模拟队列,BFS模版用的是queue
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
bool topsort()
{
for(int i = 1; i <= n; i ++) // 首先将所有入度为0的点入队。
if(!d[i]) q[++ tt] = i;
while(hh <= tt) // 队列中有元素
{
int t = q[hh ++];
for(int i = h[t]; i != -1; i = ne[i]) // BFS搜索
{
int j = e[i];
d[j] --; // 搜到一个点,将该点入度减1.
if(d[j] == 0) q[++ tt] = j; // 如果为0,那就入队
}
}
return tt == n - 1; // 判断最后是否是n个顶点都入队了。
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h); // 初始化单链表队头
for(int i = 0; i < m; i ++) // 读入所有的边。
{
int a, b;
cin >> a >> b;
d[b] ++; // b点的入度加1
add(a, b);
}
if(topsort())
{
for(int i = 0; i < n; i ++)
cout << q[i] << ' ';
cout << endl;
}
else cout << "-1" << endl;
return 0;
}
原文地址:https://blog.csdn.net/weixin_60278491/article/details/144385123
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!