拓扑排序

一、基本概念

在一个有向无环图(Directed Acyclic Graph, DAG)中,规定< u,v > 表示一条由u指向v的的有向边。要求对所有的节点排序,使得每一条有向边 < u,v>中u都排在v的前面。

换个形象点的解释,我们在学习一门课程之前,应该需要一定的预备知识,比如在学习B课程之前我们需先学习A(后用< X,Y > 表示X课程是Y课程的预备知识,其实与上述有序偶的含义相同),则有 < A,B >。我们还有 < C,B >, < B,D >, < E,D >, < D,F >, < D,G >, < H,G >. 现在要求你合理安排A-H这些课程的学习顺序。这个任务的要求实际上就是对A-H进行拓扑排序。

为何要求这个图是DAG呢?不难想象,如果上面的课程变成 < A,B >, < B,C >, < C,D > …… < H,A >. (即A-H成有向环)那么我们就无法判断出先学哪个课程了。

二、算法实现

以上面给课程排序为例,我们首先要学的,一定是一个不需要任何预备知识的课程,然后学完这个课程之后,根据边的关系再看有哪些新的课程可以学习,同时我们还要清楚,学完一门课程后,就不需要再次学习这一门课程了

我们将其与图做个类比。

不需要预备知识的课程-> 入度为0的点

新的课程->所指向的下一个点

每门课之学一次->从图中删除节点 && 从图中删除有向边

接着再根据图类比结果决定存储的数据

入度为0的点->需要存储每个节点的入度

所指向的下一个点->需要存每个节点的后继

删除节点与有向边-> 这里讨论一下:

如果我们真的删除了节点和有向边,那就意味着无法在找到这些数据了。因为我们还需要判断是否形成了DAG,最保险的做法是将下一个节点的入度-1。如果发现某个节点的入度为-1了,表明存在有向环,那么说明不存在与拓扑排序。

根据存储的数据选择数据结构(具体情况具体分析,灵活变通)

节点入度->数组

节点后继->vector

三、例题讲解

UVA.10305 Ordering Tasks

有n个点,m条边,给n个顶点做拓扑排序。

  1. #include <iostream>
  2. #include <iostream>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #include <cstring>
  6. #include <sstream>
  7. #include <set>
  8. #include <map>
  9. #include <queue>
  10. #include <stack>
  11. #include <cmath>
  12. #define nmax 200
  13. #define MEM(x) memset(x,0,sizeof(x))
  14. using namespace std;
  15. vector<int> v[nmax];
  16. int indegree[nmax];
  17. int n;
  18. bool suc = true;
  19. queue<int> ans;
  20. void topsort()
  21. {
  22. queue<int> q;
  23. while(1){
  24. for(int i = 1; i<=n ;++i){
  25. if(indegree[i] == 0){
  26. q.push(i);
  27. ans.push(i);
  28. indegree[i] = -1;
  29. }
  30. }
  31. if(q.empty()) break;
  32. while(!q.empty()){
  33. int t = q.front(); q.pop();
  34. for(int j = 0;j<v[t].size();++j){
  35. int tt = v[t][j];
  36. if(indegree[tt] == -1){
  37. suc = false;
  38. break;
  39. }else indegree[tt]--;
  40. }
  41. v[t].clear();
  42. if(!suc) break;
  43. }
  44. if(!suc) break;
  45. }
  46. if(ans.size() <n){
  47. suc =false;
  48. return;
  49. }
  50. }
  51. void output()
  52. {
  53. bool isfirst = true;
  54. while(!ans.empty()){
  55. int t = ans.front(); ans.pop();
  56. if(isfirst){
  57. printf("%d",t);
  58. isfirst = false;
  59. }else
  60. printf(" %d",t);
  61. }
  62. printf("\n");
  63. }
  64. int main()
  65. {
  66. //freopen("in.txt","r",stdin);
  67. int m;
  68. while(scanf("%d%d",&n,&m) ==2 && (n||m)){
  69. MEM(indegree);
  70. suc = true;
  71. int a,b;
  72. for(int i = 0; i<m; ++i){
  73. scanf("%d%d",&a,&b);
  74. indegree[b]++;
  75. v[a].push_back(b);
  76. }
  77. topsort();
  78. if(suc) output();
  79. else printf("failed\n");
  80. }
  81. return 0;
  82. }

基本方法是,indegree表示入度表,vector存后继节点。在topsort函数中,制造一个辅助队列,首先从入度表中找到入度为0的点作起点,并且置入度为-1。接着依次处理队列中的节点,首先根据他们的后继,将其后继节点的入度依次减1,若其后继节点中的入度存在-1的,说明成环,则不存在拓扑排序。紧接着再从入度表中找到入度为0的节点,加入到队列中,直到队列空。当退出while循环的时候,需要检查ans答案队列中是否已经有全部的节点,若其数量为n,则表明存在拓补排序,否则不存在。

当然本题满足存在topsort。下面给出三组例子,可以检验一下自己程序的健壮性。

Graph1

不存在拓扑排序,节点2,3,4成环

  1. 4 5
  2. 1 3
  3. 1 2
  4. 2 3
  5. 3 4
  6. 4 2

Graph2

不存在拓扑排序,节点1,2,3成环

  1. 5 6
  2. 5 1
  3. 1 2
  4. 2 3
  5. 3 1
  6. 1 4
  7. 4 3

Graph3

存在拓扑排序

  1. 13 14
  2. 1 2
  3. 1 6
  4. 1 7
  5. 3 1
  6. 3 4
  7. 4 6
  8. 6 5
  9. 8 7
  10. 9 8
  11. 7 10
  12. 10 11
  13. 10 12
  14. 10 13
  15. 12 13

算法学习 拓扑排序(TopSort)的更多相关文章

  1. HDU.3342 Legal or Not (拓扑排序 TopSort)

    HDU.3342 Legal or Not (拓扑排序 TopSort) 题意分析 裸的拓扑排序 根据是否成环来判断是否合法 详解请移步 算法学习 拓扑排序(TopSort) 代码总览 #includ ...

  2. HDU.2647 Reward(拓扑排序 TopSort)

    HDU.2647 Reward(拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 这道题有一点变化是要求计算最后的金钱数.最少金钱值是888,最少的 ...

  3. HDU.1285 确定比赛名次 (拓扑排序 TopSort)

    HDU.1285 确定比赛名次 (拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 只不过这道的额外要求是,输出字典序最小的那组解.那么解决方案就是 ...

  4. 拓扑排序 topsort详解

    1.定义 对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列. 举例: h3 { marg ...

  5. NetworkX系列教程(10)-算法之四:拓扑排序与最大流问题

    小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...

  6. 拓扑排序 topsort

    拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序 ...

  7. 算法学习记录-排序——插入排序(Insertion Sort)

    插入排序: 在<算法导论>中是这样描述的 这是一个对少量元素进行排序的有效算法.插入排序的工作机理与打牌时候,整理手中的牌做法差不多. 在开始摸牌时,我们的左手是空的,牌面朝下放在桌子上. ...

  8. 算法学习记录-排序——冒泡排序(Bubble Sort)

    冒泡排序应该是最常用的排序方法,我接触的第一个排序算法就是冒泡,老师也经常那这个做例子. 冒泡排序是一种交换排序, 基本思想: 通过两两比较相邻的记录,若反序则交换,知道没有反序的记录为止. 例子: ...

  9. 【算法学习记录-排序题】【PAT A1012】The Best Rank

    To evaluate the performance of our first year CS majored students, we consider their grades of three ...

随机推荐

  1. eclipse导入jmeter3.1源码并运行

    jmeter3.1源码地址:https://archive.apache.org/dist/jmeter/source/ 1.打开eclipse,新建一个java project的项目,并点击next ...

  2. liunx环境下安装禅道

    环境: vm12.5.2 CentOS-7-x86_64 ZenTaoPMS.9.1.stable.zbox_64 SecureCRT 8.0 因为liunx环境下配置apache, php, mys ...

  3. mysql新手进阶01

    生活不止眼前的苟且,还有诗和远方. 请根据给出的数据库表结构来回答相应问题: DEPT (DEPTNO INT, DNAME VARCHAR(14),LOC VARCHAR(13)); EMP (EM ...

  4. 关于axios跨域带cookie

    axios  设置 withCredentials :true $u = $_SERVER['HTTP_REFERER'];$u = preg_replace('#/$#', '', $u);head ...

  5. 统计单词数:string函数使用

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  6. 深度学习图像分割——U-net网络

    写在前面: 一直没有整理的习惯,导致很多东西会有所遗忘,遗漏.借着这个机会,养成一个习惯. 对现有东西做一个整理.记录,对新事物去探索.分享. 因此博客主要内容为我做过的,所学的整理记录以及新的算法. ...

  7. 由一个hash字符串生成多个子hash字符串

    通过存储一个head hash,然后把子hash放到网络中 当然,也可以像默克尔树那样的,生成多级的子hash ,可以通过规则配置不同的hash 生成方式.倒置的默克尔树 我有一个文件,然后我把她分隔 ...

  8. kvm虚拟化操作

    本节演示如何使用 virt-manager 启动 KVM 虚机. 首先通过命令 virt-manager 启动图形界面 # virt-manager 点上面的图标创建虚机 给虚机命名为 kvm1,这里 ...

  9. POJ 3693 Maximum repetition substring(后缀数组)

    Description The repetition number of a string is defined as the maximum number R such that the strin ...

  10. JS中Text节点总结

    文本节点有Text类型表示,包含的是可以找字面解释的纯文本内容.纯文本中可以包含转移后的HTML字符,但不能包含HTML代码.Text节点具有以下属性: 1.nodeType的值为3. 2.nodeN ...