拓扑序列

概念

拓扑序列遵循一个规则,在遍历图的时候必须保证一条有向边的起点排在终点的前面

举一个例子

提供的有向边为:1 -> 2 | 2 -> 3 | 1 -> 3满足条件

1 - > 2 | 2 -> 3 | 3 -> 1就不满足条件

如何实现拓扑序列?

  • 找到所有入度为0的点,将其放入到队列中
  • 将这些点从队列中弹出,并且将这些点所指向的终点的点入度减1
  • 最后判断这些点是否入度为0,如果为0重新放入到队列中,循环这三种情况

Step1:找到入度为0的点

for(int i = 1;i <= n;i++) {
if(!in(i)) q.push(i);
}

Step2:使该点指向的终点入度减1

while(q.size()) {
int fr = q.front();
q.pop();
for(int i = h[fr];~i;i = ne[i]) {
int j = ne[i];
in[j]--;
}
}

Step3:检查入度为0,重新放入队列

while(q.size()) {
int fr = q.front();
q.pop();
for(int i = h[fr];~i;i = ne[i]) {
int j = ne[i];
in[j]--;
if(!in[j]) q.push(j);
}
}

完整代码

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int e[N],h[N],ne[N],idx;
queue<int> q;
int d[N],top[N];int n,m,cnt;
void add(int a,int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}

bool topsort() {
for(int i = 1;i <= n;i++) {
if(!d[i]) q.push(i);
}

while(q.size()) {
int t = q.front();
top[cnt++] = t;
q.pop();
for(int i = h[t];i != -1;i = ne[i]) {
int j = e[i];
d[j]--;
if(d[j] == 0) {
q.push(j);
}
}
}

return cnt == n;
}


int main(){
memset(h,-1,sizeof(h));
int a,b;
cin >> n >> m;
while(m--) {
cin >> a >> b;
d[b]++;
add(a,b);
}

if(!topsort()) {
cout << -1 << endl;
}else {
for(int i = 0;i < n;i++) {
cout << top[i] << " ";
}
cout << endl;
}

return 0;
}