AcWing 848. 有向图的拓扑序列
用BFS来写拓扑,以前还真没想过这个思路
之前用的都是深搜找拓扑序
依然是正常用数组实现一个邻接表,然后用数组模拟队列,从入度为0,即d[i] == 0的点开始搜索
用数组模拟队列的原因是为了最后方便直接输出拓扑序,就不用另开一个数组专门存储了
代码中的几个小细节:
- 把邻接表的头指针初始化为-1, memset(h, -1, sizeof h);,来表示邻接表为空,不然会死循环导致TLE
- 往队列中添加元素的操作是q[++tt] = i;,弹出元素则是hh++;或者t = q[hh++];,和这几个操作配套的一个细节是要把队尾初始为-1,int hh = 0, tt = -1;
示例代码里有很多short cut, 感觉不熟练容易写歪来= =, 比如我老是忘记初始化h[]数组,然后写完要补上一行 QwQ
代码实现
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int h[N], e[N], ne[N], idx;
int q[N], d[N];
int n, m;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
bool 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];
if(--d[j] == 0)
q[++tt] = j;
}
}
return tt == n - 1;
}
int main(){
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i = 0; i < m; i++){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
d[b] ++ ;
}
if(!toposort()) puts("-1");
else{
for(int i = 0; i < n; i++) printf("%d ", q[i]);
puts("");
}
return 0;
}