acwing 848. 有向图的拓扑序列
题目描述
给定一个 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
拓扑排序算法求解
分析
用d[u]
记录每个节点u的入度
维护一个队列q,把所有入度为0的点放入队列中
每次从队列中取一个点,遍历该点所有的邻接点,并将每个邻接点的入度-1,如果-1后该邻接点的入度也变成了0,那么将其加入队列
同时使用res[N]
记录每个进入过队列中的点
如果队列为空时,res的大小为n说明存在拓扑排序,输出即可;否则说明存在环
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 100010, M = 2*N;
int n, m;
int d[N];// 存每个节点的入度
queue<int> q; //存所有入度为0的点
int res[N], cnt = 0;
//存图
int h[N], e[M], ne[M], idx = 0;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void tor()
{
// 先把入度为0的点加入队中
for(int i = 1; i <= n; i++)
if(!d[i])
{
q.push(i);
res[cnt++] = i;
}
while(q.size())
{
int t = q.front();
q.pop();
// t所有指向的点
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
d[j]--; // 该点入度-1
if(!d[j])
{
q.push(j); // 若度为0,加入队列
res[cnt++] = j;
}
}
}
}
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] ++;
}
tor();
if(cnt < n) cout << -1 << endl;
else {
for(int i = 0; i < n; i++)
cout << res[i] << " ";
}
puts("");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】