之前没遇到过需要用拓扑序的题目,只是知道思想,没实现过,今天碰到了,写一下吧。拓扑序其实特简单,感觉不需要咋讲 。
拓扑序定义:一个DAG,将所有顶点排成一个序列,使图中任意一条有向边a->b满足a出现在b之前。
思路:
之前没接触过的我都会,说明它真的不难。QAQ 一个点的入度为0说明这个点可以当作当前图中的第一个点出现了,然后删除这个点以及和这个点相关的所有的边,在剩下的图中再次找入度为0的点,,,结束。
可以考虑记录每个点入度的个数,先将所有入度为0的点入队列,每次取出队首输出,将队头点的邻接边的入度减一,如果该操作完成后有一些点的入度变为0,也入队,不断扩展当前图中入度为0的点的个数,直到队列为空即可。
特别地,如果最后输出的点的个数小于总个数,说明有环(因为环中每个点都有入度,不存在入度为0的点)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 310;
int cnt[N], head[N], nex[N], to[N], num;
void add(int a, int b){
++num;
to[num] = b;
nex[num] = head[a];
head[a] = num;
}
int n, m;
int main() {
ios::sync_with_stdio(0);
num = 0;
mem(cnt, 0);
mem(head, -1);
mem(nex, -1);
cin >> n >> m;
cout << n << m << "\n";
while (m--){
int a, b;
cin >> a >> b;
add(a, b);
cnt[b]++;
}
queue<int> q;
for (int i = 1; i <= n; i++){
if (!cnt[i])q.push(i);
}
while (!q.empty()){
int t = q.front();
cout << t << " ";
q.pop();
for (int i = head[t]; ~i; i = nex[i]){
int y = to[i];
cnt[y]--;
if (!cnt[y]){
q.push(y);
}
}
}
return 0;
}