拓扑排序

拓扑排序

偶尔善良 提交于 2019-12-03 16:50:48
拓扑排序,首先它是一种排序。不过是应用在有向无环图上,将图的结点按照某种规则排成一个线性队列。只不过排序的规则是 对于任意两个结点(u,v),如果他们之间存在边(u->v),那么u必须出现在v之前。 满足拓扑排序的一个有向无环图 那么按照上面的规则我们可以这样实现拓扑排序 1: 找到所有初始入度为0的节点,并将它们放入队列或者栈中,并记录此时入度为0的数目。 2:遍历队列中的结点,对每一个结点,遍历它的直接相连的结点。并将它们入度减一,如果入度为0,将该节点放入队列,更新入度为0的数目(+1)。 3:重复2中操作,直到队列中元素为空,此时比较入度为0的数目和图的总结点数是否相等。如果相等,则可以满足拓扑排序(也就是判断图不存在环),反之不满足。 import java.util.Stack; /** * 为了简单起见 使用了邻接矩阵 * sort具体过程如上述所说 */ public class TopoSort { public static boolean sort(int[][] matrix, int[] degree) { Stack<Integer> stack = new Stack(); int count = 0; for (int i = 0; i < degree.length; i++) { if (degree[i] == 0) { stack.push

拓扑排序 + make + UVa10305(Ordering Tasks)

左心房为你撑大大i 提交于 2019-12-03 14:45:02
  拓扑排序在实践中应用广泛。先来看一个实例,开源软件常使用GNU make工具来管理项目的构建。这里的项目是由若干个对象构成的,Makefile文件则描述了这些对象的构建规则,这些规则具体来说是一系列对象间的依赖关系:若对象A依赖于对象B,则说明对象B必须先于对象A构建,否则构建将无法进行。make的任务就是合理安排各个对象构建的先后顺序,使得过程能顺利地完成。   作为例子,一个Makefile文件的内容如下: target: foo.o bar.o foo.o: foo.c foo.h bar.o: bar.c bar.h   为了解决这一问题,我们先对问题进行数学转化。使用DAG来表示每个对象间的依赖关系,图的每一个顶点表示一个对象、有向线段表示起点必须先于终点被构建,即终点依赖起点。   如何合理布局各个对象的构建顺序,使得构建过程可以顺利地进行下去呢?直观的想法是,选择不被其它对象依赖的作为第1个对象;再考虑第2个对象,它除了已选的第1个对象外,不应该被其它对象依赖;第n个对象,它除了前面已选的第1~n-1对象外,不能再被其它对象依赖。按照这个规则依次选出对象,即可保证构建过程顺利结束。   在图论中,这种类似的策略称为拓补排序算法。拓扑排序是所有顶点的线性排序,拓扑排序中没有一个节点指向它前面的节点,形式化地描述:对于图中的任意两个结点u和v

拓扑排序【Kahn算法(bfs)和dfs求拓扑序列及判环】

爱⌒轻易说出口 提交于 2019-12-03 12:02:01
拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,该排序满足这样的条件——对于图中的任意两个结点 u 和 v ,若存在一条有向边从 u 指向 v ,则在拓扑排序中 u 一定出现在 v 前面。 当且仅当一个有向图为有向无环图(DAG)时才存在对应于该图的拓扑排序。每一个有向无环图都 至少 存在一种拓扑排序。 拓扑排序的实现: ①Kahn算法【常可用来判断该图是否是DAG(有向无环图)】 算法复杂度为O(v+e)。 算法实现:循环执行以下两步直到不存在入度为0的顶点为止。 (1)选择一个入度为0的顶点并输出之;(2)从网中删除此顶点及其所有出边。 循环结束后,若输出的顶点数小于网中的顶点数,则该图存在回路,否则输出的顶点序列就是拓扑序列,该图也即为DAG图。 该算法可借助队列实现 。类似于bfs:首先将入度为0的顶点入队,取出队头元素进行拓展,找其邻接点,每个邻接点的入度-1,当入度变为0时则入队。循环此操作直到队列为空。出队顶点序列即为拓扑序列。 int k=0; void toposort() { queue<int>q; for(int i=1;i<=n;i++) if(!indegree[i]) q.push(i); while(!q.empty()){ int u=q.front(); q

【模板】拓扑排序

丶灬走出姿态 提交于 2019-12-03 02:34:30
(图论杀我) 定义: 对一个 有向无环图 (Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。(摘自360百科) 其实就是对于一张有向图,按照入度大小从小到大排序。 实现过程: 简单讲就是对于任意状态,先找到一个入度为0的点,记录答案后把所有与它相连的的点的入度减一,重复这个过程即可。 代码: #include<iostream> #include<vector> #include<queue> using namespace std; struct edge { int next,to; edge(){} edge(int a,int b) { next=a; to=b; } }e[1000001]; int tot,in[100001],first[100001];//邻接表存图 void add_edges(int a,int b) { e[++tot]=edge(first[a],b); first[a]=tot; in[b]++; } int n,m; int

拓扑排序-理解

﹥>﹥吖頭↗ 提交于 2019-12-03 02:25:34
用来处理有事件(点)存在先后关系的算法。 经典应用:工程图 也可以处理已知序列之间大小关系,求一组可行解。 算法流程 分析问题,抽象出点和边,建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

LeetCode | 207. 课程表

北战南征 提交于 2019-12-03 02:22:55
原题 ( Medium ):   现在你总共有 n 门课需要选,记为 0 到 n-1。   在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]   给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?    说明:   输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。   你可以假定输入的先决条件中没有重复的边。 提示:   这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。   拓扑排序也可以通过 BFS 完成。 思路:拓扑排序    只看题可能不太容易理解题意,结合给出的说明和提示,我们应该明白这题考的就是给出一个有向图的节点数和边集,查找该有向图是否有环。建立拓扑排序首先肯定就是从入度为0的节点开始,然后把其指向的节点的入度减一,如果减一后有节点的入度归零,那么就把入度归零的节点放进拓扑排序里。举一个有向图经拓扑排序后的图:   我不想在此过多讨论拓扑排序的概念。我只想讨论如何实现拓扑排序。题目给予的资源是节点数和边集,为了实现拓扑排序,我们需要一个邻接链表和入度数组,根据边集,我们可以构建图的邻接链表和入度数组。具体实现可以是:定义一个map容器,里面存放每个节点出度点的集合,集合可用set容器表示

拓扑排序判断有向图是否成环

匿名 (未验证) 提交于 2019-12-03 00:27:02
#include <cstdio> #include <cstring> #include<iostream> #include <queue> using namespace std; const int maxn = 1e5 + 7; int n,m, du[maxn], head[maxn], tot,cnt,ans[maxn]; struct node { int v, next; } edge[maxn]; queue<int>q; void add(int u, int v) { edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++; } void init() { tot = 0; memset(du, 0, sizeof(du)); memset(head, -1, sizeof(head)); } void solve() { while(!q.empty()) { int u = q.front(); q.pop(); ans[cnt++]=u; for (int i = head[u] ; i != -1 ; i = edge[i].next) { du[edge[i].v]--; if (!du[edge[i].v]) q.push(edge[i].v); } } } int main() {

图的两种拓扑排序

匿名 (未验证) 提交于 2019-12-03 00:26:01
#include <iostream> #include <vector> #include <stack> #define MaxSize 10 #define eletype int using namespace std; bool visited[MaxSize]; //全局数组,记录结点是否已补访问 int Degree[MaxSize]; //存储顶点的入度数 int time; //时间变量 int Time[MaxSize]; typedef struct edgenode { //边表结点 int adjvex; //邻接点 int weight; //权值 edgenode *next; //下一条边 }; typedef struct vertexnode { //顶点结点 eletype data; //结点数据 edgenode *fist; //指向第一条边 }AdjList[MaxSize]; typedef struct AdjListGraph { AdjList adjlist; //邻接表 int vex; //顶点数 int edge; //边数 }; void Init() { //初始化为未访问 for (int i = 0; i < MaxSize; i++) { visited[i] = false; Degree[i] = 0; }

拓扑排序的应用---leetcode207 课程表

匿名 (未验证) 提交于 2019-12-03 00:22:01
拓扑排序是有向无环图的应用,由偏序定义得到拓扑有序的操作叫做拓扑排序,拓扑有序是全序。 进行拓扑排序的方法: 1.在有向图中选一个入度为0 (即没有前驱)的节点输出 2.从图中删除该节点和以它为起点的依赖关系 3.直到全部节点输出或者当前不存在无前驱的节点为止(这种情况说明存在环)。 代码出自 http://www.zhufangxing.com/2015/05/01/leetcode-ICourse%20Schedule/ 学习一下 def canFinish ( numCourses , prerequisites ) : if numCourses < 2 or len ( prerequisites ) < 2 : print ( 'True' ) return True while True : count = 0 mark = [ True ] * numCourses ###true表示入度为0 删除与之的依赖关系 for pre in prerequisites : mark [ pre [ 0 ]] = False for pre in prerequisites : if mark [ pre [ 1 ]] : count += 1 prerequisites . remove ( pre ) if prerequisites == [] : print (

LeetCode 高级 - 课程表

匿名 (未验证) 提交于 2019-12-03 00:22:01
现在你总共有 n 门课需要选,记为 0 到 n-1 。 在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习? 示例 1: 输入: 2 , [[1,0]] 输出: true 解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。所以这是可能的。 示例 2: 输入: 2 , [[1,0],[0,1]] 输出: false 解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。 说明: 输入的先决条件是由 边缘列表 表示的图形,而不是邻接矩阵。详情请参见 图的表示法 。 你可以假定输入的先决条件中没有重复的边。 提示: 这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。 通过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。 拓扑排序也可以通过 BFS 完成。 解决这道题,我们首先要补充一下关于拓扑排序的知识。 将有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面。