拓扑排序
首先明白什么是拓扑序列?
只有有向图才会有拓扑序列,每一条边的起点都在终点之前
例如:
但如果是这样子的
有向图中存在一个环 则它就不存在拓扑序列。
拓扑图:有向无环图一定存在拓扑序列,因此有向无环图也叫做拓扑图,所有入度为0的节点都可以作为起点,因此拓扑序列并不唯一。**
有向无环图一定存在拓扑序列是因为,一定至少存在一个入度为0的点,因此可以逐个突破,生成拓扑序,而一个环上的每个点入度必不为0。
生成拓扑序列的步骤
queue <- 所有入度为0的点
while queue不为空
{
t <- 取队头
枚举t所有出边 t-j
删掉t->j j入度减一:d[j]--
if(d[j] == 0) 说明节点j的入度为0 可以作为起点入队 queue <- j
所有点全部入队 拓扑序列排序完成
}
输出拓扑序(在队列中)
而且这个题体现出了用数组模拟queue的好处,用队列数组储存的正好是拓扑序
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int q[N], d[N]; //d用来存一个点的入度
bool torsort()
{
int hh = 0, tt = 0;
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])
{
int j = e[i];
d[j]--; //删出边
if(d[j] == 0) q[++tt] = j; //入队
}
}
return tt == n; //所有点都入队 则完成拓扑序
}
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
d[b]++; //入度加1
}
if(torsort())
{
for(int i = 1; i <= n; i++) printf("%d ", q[i]);
puts("");
}
else puts("-1");
system("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端