思想
拓扑排序本质上就是把一个有向无环图(DAG)变成一个线性序列,给定DAG中两个点u,v,若<u,v>∈E(G),那么在线性序列中,u一定在v前面。
有向无环图一定可以拓扑排序,有向有环图一定不能拓扑排序。
例题
ACWING848 拓扑排序
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int h[N], e[N], ne[N], q[N], d[N], idx, n, m;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
int toposort()
{
int hh = 0, tt = -1;
for(int i = 1; i <= n; i++)
{
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])
q[++tt] = j;
}
}
return tt == n - 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int a, b;
memset(h, -1, sizeof h);
cin >> n >> m;
while(m--)
{
cin >> a >> b;
add(a, b);
d[b]++;
}
if(toposort())
for(int i = 0; i < n; i++)
cout << q[i] << ' ';
else
cout << "-1" << '\n';
return 0;
}
核心思想与注意点:
- 调用toposort()函数后,如果队列中的元素个数等于给定图的元素个数,则说明该图是有向无环图,可以拓扑排序。
- 每次输入一条有向边,就将有向边末尾的元素入度加一。
- 拓扑排序时,先把入度为0的点全部入队,然后出队一个元素,bfs,把这个元素的邻接点入度全部减一,如果它的邻接点入度变为0,那么把它的邻接点也入队。