用来处理有事件(点)存在先后关系的算法。

经典应用:工程图
也可以处理已知序列之间大小关系,求一组可行解。

算法流程

分析问题,抽象出点和边,建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 }
View Code
01-02 20:44