基本思想

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

算法原理

在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:

每个顶点出现且只出现一次。
若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。

例如,下面这个图:


 
它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:

从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
从图中删除该顶点和所有以它为起点的有向边。
重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。


于是,得到拓扑排序后的结果是 { 1, 2, 4, 3, 5 }。

通常,一个有向无环图可以有一个或多个拓扑排序序列。

应用

拓扑排序通常用来“排序”具有依赖关系的任务。

比如,如果用一个DAG图来表示一个工程,其中每个顶点表示工程中的一个任务,用有向边<A,B>表示在做任务 B 之前必须先完成任务 A。故在这个工程中,任意两个任务要么具有确定的先后关系,要么是没有关系,绝对不存在互相矛盾的关系(即环路)。

源代码

C++版本一

 //b[]为每个点的入度
for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(b[j]==0){   //找到一个入度为0的点ans=j;vis[cnt++]=j;b[j]--;break;}}for(j=1;j<=n;j++)if(a[ans][j]) b[j]--; //与入度为0的点相连的点的入度减一
}printf("%d",vis[0]);for(i=1;i<cnt;i++) printf(" %d",vis[i]);printf("\n");

C++版本二

queue<int>q;for(int i=0;i<n;i++)  //n  节点的总数if(in[i]==0) q.push(i);  //将入度为0的点入队列vector<int>ans;   //ans 为拓扑序列while(!q.empty()){int p=q.top(); q.pop(); // 选一个入度为0的点,出队列ans.push_back(p);for(int i=0;i<edge[p].size();i++){int y=edge[p][i];in[y]--;if(in[y]==0)q.push(y);  }}if(ans.size()==n)   {for(int i=0;i<ans.size();i++)printf( "%d ",ans[i] );printf("\n");}else printf("No Answer!\n");   //  ans 中的长度与n不相等,就说明无拓扑序列

C++版本三

#include<iostream>
#include <list>
#include <queue>
using namespace std;/************************类声明************************/
class Graph
{int V;             // 顶点个数list<int> *adj;    // 邻接表queue<int> q;      // 维护一个入度为0的顶点的集合int* indegree;     // 记录每个顶点的入度
public:Graph(int V);                   // 构造函数~Graph();                       // 析构函数void addEdge(int v, int w);     // 添加边bool topological_sort();        // 拓扑排序
};/************************类定义************************/
Graph::Graph(int V)
{this->V = V;adj = new list<int>[V];indegree = new int[V];  // 入度全部初始化为0for(int i=0; i<V; ++i)indegree[i] = 0;
}Graph::~Graph()
{delete [] adj;delete [] indegree;
}void Graph::addEdge(int v, int w)
{adj[v].push_back(w); ++indegree[w];
}bool Graph::topological_sort()
{for(int i=0; i<V; ++i)if(indegree[i] == 0)q.push(i);         // 将所有入度为0的顶点入队int count = 0;             // 计数,记录当前已经输出的顶点数 while(!q.empty()){int v = q.front();      // 从队列中取出一个顶点q.pop();cout << v << " ";      // 输出该顶点++count;// 将所有v指向的顶点的入度减1,并将入度减为0的顶点入栈list<int>::iterator beg = adj[v].begin();for( ; beg!=adj[v].end(); ++beg)if(!(--indegree[*beg]))q.push(*beg);   // 若入度为0,则入栈}if(count < V)return false;           // 没有输出全部顶点,有向图中有回路elsereturn true;            // 拓扑排序成功
}

例题

http://acm.hdu.edu.cn/showproblem.php?pid=4857

参考文章

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

https://blog.csdn.net/lisonglisonglisong/article/details/45543451

拓扑排序(Topology_Sort)相关推荐

  1. 【图论】有向无环图的拓扑排序

    1. 引言 有向无环图(Directed Acyclic Graph, DAG)是有向图的一种,字面意思的理解就是图中没有环.常常被用来表示事件之间的驱动依赖关系,管理任务之间的调度.拓扑排序是对DA ...

  2. C#实现有向无环图(DAG)拓扑排序

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

  3. hdu 5438 Ponds 拓扑排序

    Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem ...

  4. usaco frame up(所有拓扑排序的输出)

    先根据图建图再拓扑排序. /** ID: jinbo wu TASK: frameup LANG:C++ */ #include<bits/stdc++.h> using namespac ...

  5. HDU1811 Rank of Tetris 拓扑排序+并查集 OR 差分约束最短路+并查集

    题目链接 题意:就是给你一堆关系,看能不能排出个确定的顺序 做法: 1. 拓扑排序+并查集 应该很容易想到的一种思路,大于小于建立单向边.对于相等的呢,就把他们缩成一个点.就用并查集缩成一个点就行了 ...

  6. C/C++二级指针概念及应用(有向图的邻接表(拓扑排序)、有向网图的邻接表、树的孩子表示)

    目录 一.概述 例1: 例2: 代码: 二.实例 1.有向图的邻接表(拓扑排序) 2.有向网图的邻接表 3.树的孩子表示 一.概述 二级指针:指向指针的指针.一般需要修改地址的时候会用到二级指针. 注 ...

  7. 极小连通子图和极大连通子图_强连通分量与拓扑排序

    前言 由于GacUI里面开始多处用上拓扑排序,我决定把之前瞎JB搞出来的算法换掉,换成个正式的.之前我自己弄了个写起来很简单的算法,然后每一处需要用到的地方我就重新做一遍.当然这样肯定也是不行的,我觉 ...

  8. 图论之拓扑排序 poj 2367 Genealogical tree

    题目链接 http://poj.org/problem?id=2367 题意就是给定一系列关系,按这些关系拓扑排序. #include<cstdio> #include<cstrin ...

  9. 用拓扑排序检测有向图中是否有环

    目录 算法主要步骤 代码 测试数据 提示:由于拓扑排序的检测方式不涉及到边权或点权,所以拓扑序列中的正环和负环都能够被检测出来.检测可达负环可以用Bellman-Ford或者SPFA. 算法主要步骤 ...

最新文章

  1. “中序表达式”转“后续表达式”
  2. Apache Dubbo 高危漏洞通告
  3. html图片在ie中有边框,html – 表格的边框在IE中不起作用
  4. hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (背包问题)
  5. 聚焦智造 共筑生态——“2016智能硬件生态圈品牌交流会”即将举行
  6. ntfs分配单元大小怎么选_星月菩提尺寸大小怎么选
  7. 某一个物种能够在 1 分钟之内干掉资深程序员...网友称:恐怖如斯!
  8. FMS 中文帮助 (下载)
  9. java ear和war_JAR、WAR、EAR的使用和区别
  10. 定损是保险公司定还是4s店定的?
  11. 《学习OpenCV3》第10章 滤波与卷积
  12. AMD劲升6% 业界分析师看好其服务器芯片Ebyc
  13. 深度学习入门系列(总结篇)
  14. 微信小程序获取用户openid(详解)
  15. DLL load failed while importing _imaging怎么处理
  16. 宏晶微MS2109高清视频采集芯片资料
  17. python参考书目_Python 阅读书目推荐
  18. 块存储、文件存储、对象存储及内容分发CDN
  19. cubemx—编码器测速(其中遇到的问题分析以及部分解决办法)
  20. 游戏修改器制作教程一:键盘鼠标模拟

热门文章

  1. python自定义全局异常_Django 自定义404 500等错误页面的实现
  2. matlab中删除照片_如何使用matlab从图像中删除划痕
  3. 苹果手机夜间模式怎么设置_微信夜间模式终于来了,苹果和安卓都适用!
  4. java文本编辑器 运行_能编译运行java的简单文本编辑器
  5. python super
  6. java jpa hibernate_java - JPA和Hibernate - Criteria与JPQL或HQL
  7. 怎么看rx580是不是470刷的_怎么看钻石是不是奶咖钻,钻石证书上可以看出奶咖钻石吗...
  8. 中国工科计算机专业,中国最受欢迎的4个工科专业,第1名有些意外,第3名副其实...
  9. 科学计算机怎么算坐标,用科学计算器fx-5800算坐标怎么按
  10. python编写ftp客户端_用Python写FTP客户端程序