<学习笔记> 拓扑排序

定义:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。(引自百度百科)

条件:有向无环图。

拓扑排序的步骤:

1.找出入度为0的点

2.删除这个点和这个点连出的所有边。

3.若已经没有入度为0的点,排序结束。

 

循环结束后,若输出的顶点数小于图中的顶点数,就说明存在着环。

由于拓扑排序可以保证一条边的起点一定比他的终点早出现,所以可以用于解决一些奇奇怪怪的问题和对一些算法进行优化(如差分、前缀处理)。

我们求拓扑排序通常会用到队列。

每次弹出对头元素,并把它的出边所连向的点入度--,如果入度为0,就压入队列,正确性显然。

 

例题 洛谷 3183 HAOI2016 食物链

代码

 1 #include<iostream> 
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 
 9 int N,M,a,b,cnt,Ans=0;
10 int first[100010],next[200010],rd[100010],ans[100010];
11 int app[100010];
12 
13 struct maple{
14     int f,t;
15 }Rode[200010];
16 
17 void Build(int f,int t)
18 {
19     Rode[++cnt]=(maple){f,t};
20     next[cnt]=first[f];
21     first[f]=cnt;
22 }
23 
24 queue<int> q;
25 int main()
26 {
27     scanf("%d%d",&N,&M);
28     for(int i=1;i<=M;++i)
29     {
30         scanf("%d%d",&a,&b);
31         Build(a,b);
32         ++rd[b],++app[a],++app[b];
33     }
34     for(int i=1;i<=N;++i)
35        if(!rd[i]&&app[i])
36        {
37            ans[i]=1;
38            q.push(i);
39        }
40     while(!q.empty())
41     {
42         int A=q.front();
43         q.pop();
44         int f=0;
45         for(int i=first[A];i;i=next[i])
46         {
47             f=1;
48             --rd[Rode[i].t];
49             ans[Rode[i].t]+=ans[A];
50             if(!rd[Rode[i].t]) q.push(Rode[i].t);
51         }
52         if(!f) Ans+=ans[A];
53     }
54     printf("%d",Ans);
55     return 0;
56 }

 

posted @ 2017-11-07 17:03  loi_maple  阅读(220)  评论(0编辑  收藏  举报