拓扑排序

拓扑排序

从离散数学的角度定义,假设(A,≤)是有限偏序集,对其进行拓扑排序是指将其扩展成一个全序集,使得≤∈<,即对任意的a,b∈A,若a≤b,则a<b。

从图论的角度定义,对一个有向无环图G进行拓扑排序,是将G中所有的顶点排成一个线性序列,使得图中任意一对顶点u和v,如果(u,v)∈E(G),则u在线性序列中应出现在v之前。

思路

从离散数学的角度定义,拓扑排序是针对有限偏序集的,由离散数学的知识知,若(A,≤)是偏序集,则拟序集(A,<)中不存在长度大于1的环(这其实与无环图对应),所以有限偏序集可以画成哈斯(Hasse)图。Hasse图非空时总存在极小元,每次输出极小元,更新Hasse图,直到Hasse为空。

从图论的角度,极小元等同于图中入度为0的顶点,每次输出入度为0的点,更新与之相连点的入度,直到输出全部顶点。如果存在顶点没有输出,说明存在环。

样题

给任务排序(UVa10305)

假设有n个任务,还有m个二元组(u,v),(u,v)表示u必须在v之前执行。请输出n个任务按顺序执行的一种可能情况。

代码实现

邻接矩阵+队列

 1 #include<stdio.h>
 2 #include<cstring>
 3 #include<queue>
 4 #include<vector>
 5 using namespace std;
 6 
 7 const int V = 100 + 10;            //最大顶点数
 8 const int E = 100 * 100 + 10;    //最大边数
 9 vector<int>e[V];        //邻接矩阵存图
10 int in[V];                //顶点的入度
11 
12 int m, n;
13 
14 int main()
15 {
16     while (scanf("%d%d", &n, &m) == 2 && n)
17     {
18         for (int i = 0; i < n; i++)        
19         {
20             e[i].clear();
21             in[i] = 0;
22         }
23         for (int i = 0; i < m; i++)
24         {
25             int from, to;
26             scanf("%d%d", &from, &to);
27             e[from].push_back(to);
28             in[to]++;
29         }
30         vector<int>ans;
31         queue<int>q;
32         for (int i = 1; i <= n; i++)  if (!in[i])    q.push(i); //将入度为0的入队
33         while (!q.empty())
34         {
35             int u = q.front(); q.pop();
36             ans.push_back(u);
37             for (int i = 0; i < e[u].size(); i++)        //遍历与之相连的顶点
38                 if ((--in[e[u][i]]) == 0)  q.push(e[u][i]);    //入度减1,如果为0,入队
39         }
40         for (int i = 0; i < ans.size(); i++)
41             printf("%d ", ans[i]);
42         printf("\n");
43     }
44     return 0;
45 }

 dfs

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<cstring>
 7 using namespace std;
 8 
 9 const int maxn = 100 + 10;
10 vector<int>G[maxn];
11 int c[maxn], topo[maxn], t;
12 int n, m;
13 
14 bool dfs(int u)
15 {
15 if(vis[u]==1) return true;
16 c[u] = -1; //正在访问,dfs(u)正在栈帧中,尚未返回 17 for (int i = 0; i < G[u].size(); i++) 18 {
20      if (c[G[u][i]] < 0) return false; 22 else if (!c[G[u][i]] && !dfs(G[u][i])) return false;
24 } 25 c[u] = 1; //已经访问过,dfs(u)已被调用过,并已访问 26 topo[--t] = u; 27 return true; 28 } 29 30 bool toposort() 31 { 32 t = n; 33 memset(c, 0, sizeof(c)); 34 for (int i = 1; i <= n; i++) 35 if (!c[i] && !dfs(i)) //c[i]为0表示从未访问过 36 return false; 37 return true; 38 } 39 40 void slove() 41 { 42 if (toposort()) 43 { 44 for (int i = n - 1; i >= 0; i--) 45 printf("%d ", topo[i]); 46 printf("\n"); 47 } 48 } 49 50 int main() 51 { 52 int u, v; 53 while (scanf("%d%d", &n, &m) == 2 && n) 54 { 55 for (int i = 0; i <= n; i++) G[i].clear(); 56 for (int i = 0; i < m; i++) 57 { 58 scanf("%d%d", &u, &v); 59 G[v].push_back(u); 60 } 61 slove(); 62 } 63 return 0; 64 }

 参考链接:

https://baike.baidu.com/item/拓扑排序/5223807?fr=aladdin

https://blog.csdn.net/qq_41713256/article/details/80805338

中国大学mooc  刘铎  离散数学

posted @ 2018-11-02 16:54  Rogn  阅读(788)  评论(0编辑  收藏  举报