用来处理有事件(点)存在先后关系的算法。
经典应用:工程图
也可以处理已知序列之间大小关系,求一组可行解。
算法流程
分析问题,抽象出点和边,建DAG图,方向是先开始的指向后开始,维护每个顶点的入度。
将入度为0的顶点放入队列中,BFS即可。BFS过程中,每遍历一次u->v,将这条边删去,即v入度减一,若v入度为0也放入队列中。
直到队列为空,算法结束。可以将队列中的不同点个数存起来,若等于n则存在拓扑序,否则该图不存在拓扑结构。DAG一定存在。
显然拓扑排序的时间复杂度为O(n+e)。
如果一个DAG有n个顶点,e条边,在拓扑排序的过程中,搜索入度为零的顶点所需的时间是O(n)。
在正常情况下,每个顶点进一次栈,出一次栈,所需时间O(n)。每个顶点入度减1的运算共执行了e次。
所以总的时间复杂为O(n+e)。

1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef pair<int,int> piir;
4 typedef long long ll;
5 const int maxn = 1e2+5;
6 const int INF = 0x3f3f3f3f;
7
8 int n,m;
9 int in[maxn];
10 vector<int> G[maxn],ans;
11 queue<int> q;
12
13 void top(){
14 while(!q.empty()) q.pop();
15 for(int i=1;i<=n;i++)
16 if(in[i]==0) q.push(i);
17
18 while(!q.empty()){
19 int u=q.front();q.pop();
20 ans.push_back(u);
21 for(auto v : G[u]){
22 in[v]--;
23 if(in[v]==0) q.push(v);
24 }
25 }
26 }
27 void init(){
28 memset(in,0,sizeof(in));
29 ans.clear();
30 for(int i=1;i<=n;i++)
31 G[i].clear();
32 }
33 int main(){
34 while(scanf("%d%d",&n,&m) && n+m){
35 init();
36 for(int u,v,i=1;i<=m;i++){
37 scanf("%d%d",&u,&v);
38 G[u].push_back(v);
39 in[v]++;
40 }
41 top();
42
43 for(auto it : ans)
44 printf("%d ",it);
45 printf("\n");
46 }
47 return 0;
48 }
