题解:AcWing 848 有向图的拓扑序列
【题目来源】
AcWing:848. 有向图的拓扑序列 - AcWing题库
【题目描述】
给定一个\(n\)个点\(m\)条边的有向图,点的编号是\(1\)到\(n\),图中可能存在重边和自环。请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出\(-1\)。
若一个由图中所有点构成的序列\(A\)满足:对于图中的每条边\((x,y)\),\(x\)在\(A\)中都出现在\(y\)之前,则称\(A\)是该图的一个拓扑序列。
【输入】
第一行包含两个整数\(n\)和\(m\)。
【输出】
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。否则输出\(-1\)。
【输入样例】
3 3
1 2
2 3
1 3
【输出样例】
1 2 3
【解题思路】

【算法标签】
《AcWing 848 有向图的拓扑序列》 #拓扑排序# #BFS#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100010; // 最大节点数
int n; // 节点数量
int m; // 边数量
int h[N]; // 邻接表头数组
int e[N]; // 边的终点数组
int ne[N]; // 下一条边数组
int idx; // 边的索引
int q[N]; // 队列,用于存储拓扑序列
int d[N]; // 入度数组,d[i]表示节点i的入度
// 添加有向边 a->b
void add(int a, int b)
{
e[idx] = b; // 存储边的终点
ne[idx] = h[a]; // 新边指向原来的第一条边
h[a] = idx; // 更新头指针指向新边
idx++; // 边索引增加
}
// 拓扑排序函数
// 返回值:true - 存在拓扑序列,false - 存在环
bool topsort()
{
int hh = 0; // 队列头指针
int tt = -1; // 队列尾指针
// 第一步:将所有入度为0的节点加入队列
for (int i = 1; i <= n; i++)
{
if (!d[i]) // 入度为0
{
q[++tt] = i; // 入队
}
}
// 第二步:BFS处理队列中的节点
while (hh <= tt) // 队列不为空
{
int t = q[hh++]; // 出队
// 遍历节点t的所有邻接点
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i]; // 邻接点j
d[j]--; // 删除边t->j,j的入度减1
// 如果j的入度变为0,加入队列
if (d[j] == 0)
{
q[++tt] = j;
}
}
}
// 第三步:判断是否所有节点都被处理
// 如果队列中有n个节点,说明存在拓扑序列
return tt == n - 1;
}
int main()
{
// 输入节点数和边数
cin >> n >> m;
// 初始化邻接表
memset(h, -1, sizeof(h));
// 读入m条有向边
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
add(a, b); // 添加边 a->b
d[b]++; // b的入度加1
}
// 执行拓扑排序
if (topsort())
{
// 输出拓扑序列
for (int i = 0; i < n; i++)
{
printf("%d ", q[i]);
}
puts(""); // 换行
}
else
{
// 存在环,无法进行拓扑排序
puts("-1");
}
return 0;
}
【运行结果】
3 3
1 2
2 3
1 3
1 2 3
浙公网安备 33010602011771号