#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
// 【有向图】的 BFS 的一个应用
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int q[N], d[N]; // Topological seq; Rudu
void add(int a, int b)
{
//Jia bian mu ban
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
/*
拓扑原理:
循环:
1. 选择一个入度为 0 的顶点,并将它输出;
2. 删除图中从该顶点连出的所有边
直到没有点位置
若输出的顶点小于图中点数,则有环,无法构造拓扑序列,否则就输出拓扑序列。
*/
bool topsort()
{
int head = 0, tail = -1;
for (int i = 1; i <= n; i++)
if (!d[i]) //所有入度为0的点i,加入待处理的队中
q[ ++ tail] = i;
//我们每次找到入度为0的点来操作。(删掉他周围点的边,然后判断入度)
//shuzu mo ni queue
while (head <= tail)
{
int t = q[head++]; //dui tou yidong yiwei 【出队】取出队头
// head += 1 即q.pop() 弹出队中。 因为下面已经要枚举这个点的几条出边了,bfs原理就是有要求弹出被计算过的点
// mei tiao chu bian枚举每条出边.
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i]; // 当前出边【i是t点的出边】【j就是i节点的值(邻接表e[i])】
d[j] --; //j的入度 -1
if (d[j] == 0) q[++tail] = j; //j就是入度为0的点了,就加入队中
}
// 【分析】: q的下标每次+1,且每次进来的都是入度为0的点,所以queue队中是拓扑序列
}
// 判断是否所有点都入队, tail == n-1 所有点都进
return tail == n - 1; //(n个点都进了,如果不是则有环)
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h); //biao tou chu shi hua
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
add(a, b);
d[b] ++; //a指向了b,所以b的入度+1
}
if (topsort())
{
for (int i = 0;i < n; i++) cout << q[i] << ' ';
puts("");
}
else puts("-1"); //Bu cun zai jiu -1
return 0;
}
使用栈
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
// 【有向图】的 BFS 的一个应用
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int d[N]; // Topological seq; Rudu
queue<int> q;
int top[N];
int cnt = 0;
void add(int a, int b)
{
//Jia bian mu ban
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
/*
拓扑原理:
循环:
1. 选择一个入度为 0 的顶点,并将它输出;
2. 删除图中从该顶点连出的所有边
直到没有点位置
若输出的顶点小于图中点数,则有环,无法构造拓扑序列,否则就输出拓扑序列。
*/
bool topsort()
{
//int head = 0, tail = -1;
for (int i = 1; i <= n; i++)
if (!d[i]) //所有入度为0的点i,加入待处理的队中
q.push(i);
//我们每次找到入度为0的点来操作。(删掉他周围点的边,然后判断入度)
//shuzu mo ni queue
while (q.size())
{
int t = q.front(); //dui tou yidong yiwei 【出队】取出队头
q.pop();
top[cnt] = t; //直接加入数组中。(即后面不用再弹出队列输出了)
cnt ++;
// head += 1 即q.pop() 弹出队中。 因为下面已经要枚举这个点的几条出边了,bfs原理就是有要求弹出被计算过的点
// mei tiao chu bian枚举每条出边.
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i]; // 当前出边【i是t点的出边】【j就是i节点的值(邻接表e[i])】
d[j] --; //j的入度 -1
if (d[j] == 0) q.push(j); //j就是入度为0的点了,就加入队中
}
// 【分析】: q的下标每次+1,且每次进来的都是入度为0的点,所以queue队中是拓扑序列
}
// 判断是否所有点都入队, tail == n-1 所有点都进
if (cnt < n) return 0;
else return 1;
//return tail == n - 1; //(n个点都进了,如果不是则有环)
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h); //biao tou chu shi hua
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
add(a, b);
d[b] ++; //a指向了b,所以b的入度+1
}
if (topsort())
{
for (int i = 0;i < n; i++) cout << top[i] << ' ';
puts("");
}
else puts("-1"); //Bu cun zai jiu -1
return 0;
}