拓扑排序

拓扑排序

懵懂的女人 提交于 2019-11-27 22:02:46
有向无环图 如果一个有向图的任意顶点之间都无法通过一些有向边回到自身,那么称这个有向图为有向无环图(Directed Acyclic Graph,DAG). 拓扑排序 拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u,v,如果存在边u->v,那么在序列中u一定在v前面,这个序列又被称为拓扑序列。 求解拓扑序列的方法 步骤如下: 一、定义一个队列Q,并把所有入度为0的结点加入序列。 二、取队首结点,输出。然后删除所有从它出发的边,并令这些边到达的顶点的入度减1,如果某个顶点的入度减为0,则将其加入队列。 三、反复进行步骤二,直到队列为空,如果队列为空时入过队的结点数目恰好为N,说明拓扑排序成功,图G为有向无环图,否则,拓扑排序失败,图G中有环。 可使用邻接表来实现拓扑排序。显然,由于需要记录结点的入度,因此需要额外建立一个数组inDegree[MAXV],并在程序一开始读入图时就记录好每个结点的入度。接下来就只需要按上面的步骤进行实现即可。 拓扑排序的代码如下: #include<bits/stdc++.h> using namespace std; vector<int>G[MAXV];//邻接表 int n,m,inDegree[MAXV];//顶点数,入度 //拓扑排序 bool topologicalSort(){ int num=0;/

hdu 2647 拓扑排序 逆向建树

ぃ、小莉子 提交于 2019-11-27 15:38:27
Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards. The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a's reward should more than b's.Dandelion's unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work's reward will be at least 888 , because it's a lucky number. Input One line with two integers n and m ,stands for the number of works and the

hdu5695 拓扑排序(模板)

大兔子大兔子 提交于 2019-11-27 15:16:39
Gym Class Time Limit: 6000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2800 Accepted Submission(s): 1040 Problem Description 众所周知,度度熊喜欢各类体育活动。 今天,它终于当上了梦寐以求的体育课老师。第一次课上,它发现一个有趣的事情。在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的ID,从1到 N ,在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作为自己评价这堂课的分数。麻烦的是,有一些同学不希望某个(些)同学排在他(她)前面,在满足这个前提的情况下,新晋体育课老师——度度熊,希望最后的排队结果可以使得所有同学的评价分数和最大。 Input 第一行一个整数 T ,表示 T ( 1 ≤ T ≤ 30 ) 组数据。 对于每组数据,第一行输入两个整数 N 和 M ( 1 ≤ N ≤ 100000 , 0 ≤ M ≤ 100000 ) ,分别表示总人数和某些同学的偏好。 接下来 M 行,每行两个整数 A 和 B ( 1 ≤ A , B ≤ N ) ,表示ID为 A 的同学不希望ID为 B 的同学排在他(她)之前

可达性统计(拓扑排序 + 状态压缩)

半城伤御伤魂 提交于 2019-11-27 13:05:45
可达性统计 题目地址(牛客) 一道比较经典的拓扑排序题 题目描述 给定一张 \(N\) 个点 \(M\) 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。 \(N,M≤30000\) 。 题解 设从点 u 出发能够到达的点构成的集合是 f(u),从点 u 出发能够到达的点,是从 u 的各个后继节点 v 出发能够到达的点的并集,再加上点 u 自身。先按照拓扑排序算法求出拓扑序,然后按照拓扑序的倒叙进行计算------因为在拓扑序中,任意一条边 (u ,v),u 都排在 v 之前。倒序处理即可。 Code #include<algorithm> #include<iostream> #include<cstdio> #include<bitset> #include<cmath> #include<queue> #define N 30007 using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return x * f; } int

Legal or Not-拓扑排序判环

点点圈 提交于 2019-11-27 08:17:40
Legal or Not 简单拓扑排序判环 Description ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many “holy cows” like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost “master”, and Lost will have a nice “prentice”. By and by, there are many pairs of “master and prentice”. But then problem occurs: there are too many masters and too many prentices, how can we know whether it is

POJ 3249 Test for Job (拓扑排序+DP)

大憨熊 提交于 2019-11-27 03:49:00
POJ 3249 Test for Job (拓扑排序+DP) < 题目链接 > 题目大意: 给定一个有向图(图不一定连通),每个点都有点权(可能为负),让你求出从源点走向汇点的路径上的最大点权和。 解题分析: 想到拓扑排序就好做了,然后在拓扑的过程中进行简单的状态转移。 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <queue> using namespace std; const int maxn = 1e5 + 7,M = 1e6 + 7; int n , m; std::vector<long long> g[maxn]; int ou[maxn],in[maxn]; long long dp[maxn],w[maxn]; struct Edge{ int to,nxt; }e[M]; int cnt,head[maxn]; inline void add(int u,int v){ e[cnt]=(Edge){ v,head[u] };head[u]=cnt++; } void init(){ cnt = 0; memset(head,-1,sizeof head); memset(dp,-0x3f,sizeof

2018 ECNA Regional Contest J. Watch Where You Step

為{幸葍}努か 提交于 2019-11-27 02:29:51
题目链接: Watch Where You Step 题意 给定有向图的邻接矩阵,现在需要给该图增加边,使得如果两点可达必直接可达,求需要加边的数量。 题解 首先,如果给定 \(n\) 个结点的图中任意两点均可达,那么需要增加的边数为有向完全图的边数 $n * (n - 1) - $ 原来有的边数。 所以先将图分解为多个强连通分量,然后将强连通分量与强连通分量之间进行拓扑排序,假设拓扑排序后各个强连通分量的结点数量分别为 \(n_1, n_2, ... , n_k\) ,则强连通分量之间需要增加的边数为 $n_1 \times n_2 \times ... \times n_k + n_2 \times n_3 \times ... \times n_k + ... + n_{k - 1} \times n_k - $ 强连通分量之间的所有边数。 可以用 \(Tarjan\) 算法加拓扑排序,也可以直接用两遍 \(DFS\) 。 对原图跑一遍 \(DFS\) ,再对反向图跑一遍 \(DFS\) 。由于把强连通分量的所有边反向后还是强连通分量,而强连通分量之间的边反向后 \(DFS\) 就不可达了。第一遍 \(DFS\) 用栈记录访问顺序,第二遍根据出栈顺序 \(DFS\) ,这样就可以找出所有强连通分量了,顺便还找到拓扑序了,具体见图和代码。 #include <bits/stdc

拓扑排序

久未见 提交于 2019-11-27 00:25:26
没有用的话qaq : Ummmm…图论的大部分知识本来早就有学过,只是一直没有写成博文来梳理,但既然上了qbxt DP图论就写一篇来总结下, 主要是来听DP的,但…由于太菜的原因,DP听得天花乱坠QWQ 有向无环图的拓扑排序是将DAG中的所有节点排序为线性序列,使得对于有向无环图的所有<s,e>∈E,都有s在线性序列中出现在u的前面。 有向图中若有环则一定不存在拓扑排序,若无则一定存在拓扑排序。 一,拓扑排序的实现 拓扑排序用栈和队列都可以实现,BFS和DFS也都可以实现。 首先对于拓扑排序的主要思想,其主要思想是对于一条有向边<s,e>,点s一定要在线性序列中出现在点e前面,所以我们在初始建图的时候统计一下每一个端点的入度,如果某个点的入度为0,那说明没有边指向它(约束它),它一定可以优先排到序列的开始的位置,将入读为零的点排入序列后,与这个点对这个点相邻的限制就会解除,因为这个点已经进入了序列,它在序列里的位置一定会比它指向的点靠前,所以我们就将所有邻点的入度-1,这样再次寻找入度为0的点循环往复,直到所有点都被拍完序。 算法流程:(这里仅描述bfs和队列实现的,其余原理均相同) 1,在建图的时候统计每个点的入度大小 2,初始寻找入度为零的点将其加入队列 3,只要队列不空,取队首元素加入序列,并扫描所有邻点,将其入度-1,若某个邻点入度变为0,将其加入队列 4,队列为空

Leetcode207—课程表

白昼怎懂夜的黑 提交于 2019-11-27 00:22:36
题目描述 现在你总共有 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。 这是不可能的。 说明: 输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。 你可以假定输入的先决条件中没有重复的边。 思路 考察拓扑排序,拓扑排序,把一个有向无环图转换成一维的拓扑排序。拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。一个简单的求拓扑排序的算法:首先要找到任意入度为0的一个顶点,删除它及所有相邻的边,再找入度为0的顶点,以此类推,直到删除所有顶点。顶点的删除顺序即为拓扑排序。 利用课程之间的关系建立有向图,如果课程A之前需要完成课程B,那么在图中A指向B

hello大家好,我是拓扑排序

你。 提交于 2019-11-26 22:22:48
发几个以前写的拓扑排序,回顾一下。 拓扑排序,一般不会单独考,主要要求还是掌握好这个概念,有个感性的认识,以及能快速的写出求拓扑排序的程序,进而继续接下来对图的处理,或是比如dp之类的算法,又或者是判断有无环之类。求拓扑序主要就是运用队列,push入度为0的点,删掉它们出去的边,重复这个操作。像要是求字典序最小,就可以用优先队列。 TOJ 3993 求字典序最小的拓扑排序 1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 using namespace std; 5 6 int ans[110], in[110]; 7 bool e[110][110]; 8 int n, m; 9 int main() 10 { 11 int T, x, y; 12 scanf("%d", &T); 13 while(T--) 14 { 15 memset(e, 0, sizeof(e)); 16 memset(in, 0, sizeof(in)); 17 scanf("%d %d", &n, &m); 18 for (int i = 0; i < m; i++){ 19 scanf("%d %d", &x, &y); 20 if (!e[x][y]){ 21 e[x][y] = 1; 22 in[y]++; 23 } 24 }