拓扑排序

图论篇4——拓扑排序

允我心安 提交于 2019-12-02 13:08:32
引入 AOV网络   在 有向图 中,用顶点表示活动,用有向边<V i , V j >表示活动 i 是活动 j 的必须条件。这种有向图称为用顶点表示活动的网络(Active on vertices),简称AOV网络。 在AOV网络中,如果活动V i 必须在V j 之前进行,则存在有向边<V i , V j >,并称V i 是V j 的直接前驱,V j 是V i 的直接后继。这种前驱与后继的关系具有 传递性 和 反自反性 ,这要求AOV网络中 不能出现回路 ,即 有向环 。因此,对于给定的AOV网络, 必须先判断它是否存在有向环。 拓扑排序   检测有向环可以通过对AOV网络进行拓扑排序,该过程将各个顶点排列成一个线性有序的序列,使得AOV网络中所有的前驱和后继关系都能得到满足。 如果拓扑排序能够将AOV网络的所有顶点都排入一个拓扑有序的序列中,则说明该AOV网络中没有有向环,否则AOV网络中必然存在有向环。AOV网络的顶点的拓扑有序序列不唯一。可以将拓扑排序看做是将图中的所有节点在一条水平线上的展开,图的所有边都从左指向右。   用穿衣服的次序来描述拓扑排序,图(a)表示必须先穿某些衣服,才可以穿其他衣服,图(b)表示将拓扑排序后的有向无环图在一条水平线上展示出来。袜子和内裤属于同等级,在排序结果中谁先谁后无所谓。 算法描述 对于一个 有向无环图 (1)统计所有节点的入度

[总结]拓扑排序

大兔子大兔子 提交于 2019-12-02 12:59:34
目录 一、关于拓扑排序 二、拓扑排序的应用 例1: P1113 杂务 例2: P3116 [USACO15JAN]约会时间Meeting Time 例3: P3243 [HNOI2015]菜肴制作 例4: P1983 车站分级 一、关于拓扑排序 1. 定义 对于任意一个DAG图(Directed Acyclic Graph,有向无环图),如果一个序列a由该图所有节点组成,并且对于任意一条边 \((u,v)\) ,u在序列中的位置均在v的位置之前,我们称这样的序列为该图的拓扑序(Topological Order),求拓扑序的过程就叫做拓扑排序(Topological Sort)。 2. 实现流程 我们每次将图中入度为0的节点入队,每次由队列中的节点扩展,每次扩展将相邻点的入度减1。若扩展时相邻节点的入度为0,那么我们也将这个节点入队。 二、拓扑排序的应用 拓扑排序能够解决什么样的问题? 1. 图中是否存在环 如果图中存在环,那么在拓扑排序后,环内节点的入度一定不为0,且这些节点无法插入到队列中。 我们可以根据这个性质判断环。 void topo_sort(){ queue<int> q; for(int i=1;i<=n;i++){ if(!in[i]) q.push(i); } while(!q.empty()){ int u=q.front();q.pop(); ans[+

拓扑排序

与世无争的帅哥 提交于 2019-12-02 12:11:09
拓扑排序 对于DAG内所有节点,生成的序列 DAG内所有节点出现且仅出现一次 若u->v,则排序时u的位置在v前面 可用于判环 queue<int> q; int in[maxn],p; //in[]:入度 p:计数器/指针 int topo[maxn]; //topo[]:拓扑序[把拓扑排序的序列放到topo数组中存储,使用拓扑序时直接调用topo数组] bool toposort(int n) { //n为图中的节点数 for(int u=1;u<=n;u++) //遍历所有节点出度 { for(int i=head[u];i;i=e[i].next)  //邻接表(链式前向星)存图所使用的遍历 { int v=e[i].to; in[v]++; //u->v,所以v点入度+1 } if(!in[u]) //若入度==0,则放入队列 { q.push(u); } } while(!q.empty()) { int u=q.front(); //取出的节点顺序为topo序 q.pop(); topo[++p]=u; if(p>n) return false; //若p>n,说明有环(拓扑序内的节点数一定与DAG中节点数相同) for(int i=head[u];i;i=e[i].next) { //链遍历 int v=e[i].to; in[v]--; //每一个与u相连的点入度

2019E0_G 生日宴会

最后都变了- 提交于 2019-12-02 10:30:52
生日宴会 题目 知识点:拓扑排序,优先队列 贝克兰德的富商道恩.唐泰斯将要举办他的生日宴会,他将要邀请n个客人。现在他面临一个问题,安排客人的到场顺序。 在贝克兰德的社交礼仪中,一场宴会的客人总是一个接一个地到达,也就是说,没有两个客人可以在同一时间到达。到达顺序也有一定的限制,大佬应该在小弟全部到场后再到,丈夫应该在妻子之前入场等等。 满足礼仪的顺序有多种,但是因为不同的客人,道恩对他们的熟悉度程度不同,他想要在满足礼仪的情况下,使得他熟悉的人先到场。 现在,道恩对客人按照熟悉程度进行编号1-n,其中1号他最熟悉。然后客人之间有m个到场顺序限制。现在请你生成一个排序,使得在满足到场限制的条件下,使得1号尽可能早的入场,然后2号,3号……以此类推 输入 第一行两个正整数n,m(1≤n≤105,0≤m≤2×105) 接下来m行,每行两个整数x,y,表示x应该比y先到 (1≤x,y≤n) 输出 一行,n个人的排序,保证有解 输入样例 3 1 3 1 输出样例 3 1 2 输入样例 5 6 2 1 5 2 4 1 5 4 3 1 5 3 输出样例 5 2 3 4 1 思路 可能比较难想。 首先,只看礼仪部分的话,就是一个有向无环图的拓扑排序。 然后,考虑熟悉程度,可能会想到用一个优先队列来代替拓扑排序的队列。但是,按照正序,不一定满足题意,比如3->1,2。所以需要考虑逆序

模拟测试66

我们两清 提交于 2019-12-01 06:38:12
T1:   每行每列都可以交换,其实就是错位排列。   写出递推式,打个高精就行了。     $f_n=(f_{n-1}+f_{n-2})*(n-1)$。   时间复杂度$O(nc)$。 T2:   可以暴力用bitsetAC。   直接建图跑拓扑,判断所有点的入度和能到达它的的点数是否相同。   用bitset维护连通集合。   若图Q是传递的,对于P中的每一条边$<u,v>$,一定不存在$u$到$v$的通路,否则与Q传递矛盾。   也就是说,仅当总的图无环,才满足条件。   直接拓扑排序即可。   时间复杂度$O(n^2)$。 T3:   数位DP。 来源: https://www.cnblogs.com/hz-Rockstar/p/11655798.html

P1983 车站分级(拓扑排序)

心不动则不痛 提交于 2019-12-01 04:56:16
稠密图的拓扑排序,建图比较抽象,从起始站到终点站所有未访问的站台向已访问的站台连一条边 然后跑拓扑排序,记录一下每个节点对应的最大答案,最后输出即可 注意稠密图就别vector了,会究极MLE 并且由于有重边,每次删边的时候要让度数减去入边的条数,否则有些点一辈子也进不了队 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&b) #define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c) #define scs(a) scanf("%s",a) #define schar(a) scanf("%c",&a) #define pr(a) printf("%lld",a) #define fo(i,a,b) for(int i=a;i<b;++i) #define re(i,a,b) for(int i=a;i<=b;++i) #define rfo(i,a,b) for(int i=a;i>b;--i) #define rre(i,a,b) for(int i=a;i>=b;--i) #define prn() printf("\n")

拓扑排序找最大环最小环

爱⌒轻易说出口 提交于 2019-11-30 18:17:43
找最大环 P5145 漂浮的鸭子 题意很明确:求图中的最大环 今天新学到的一种方法—— 拓扑排序求环 由于拓扑排序每次都是从入度为0的点开始,而环上的点的入度都不会为0,所以环上的点就不会参加排序,也就是说,经过拓扑排序后剩下的边和点构成的都是环。 这样我们就可以直接把每个环扫一遍记录最大环就结束了。 //2019/09/27 #include<bits/stdc++.h> using namespace std; template <typename T>inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;} #define rep(i,a,b) for(int i=(a);i<=(b);++i) #define dwn(i,a,b) for(int i=(a);i>=(b);--i) #define mem(a,b) memset(a,b,sizeof(a)) #define ee(i,u) for(int i=head[u];i;i=e[i].next) const int N=1e5+10; struct edge{

【学习】拓扑排序

烂漫一生 提交于 2019-11-30 16:21:21
前言 这个人太菜了都要CSP了才学拓扑排序 0x10 定义 给定一张有向无环图,若一个由图中所有点构成的序列A满足边(x,y),x在A中都出现在y之前,则称A是该有向无环图顶点的一个拓扑序。求解A的过程就叫做拓扑排序。                                                            ——蓝书·lyd 0x20 思想+过程 选择入度为0的点,然后把他连向的点入读减1就行了 过程: 1.建立空的序列A 2.预处理所有点的入度,把 入度为0的点入队 3.取队头x,把x放在A的末尾 4.遍历从x连出的y点,并把y的入度减1,如果这是y的入度为0,入队 5.循环3,4直至队列为空,得到A序列 0x30 用处+题目 ①判环 ②处理图上有明显先后顺序要求的题目 Luogu P1038 神经网络 Luogu P2661 信息传递 0x40 code 1 void topsort(){ 2 queue<int>q; 3 int x,v; 4 for(int i=1;i<=n;i++){ 5 if(!r[i])q.push(i);//如果入度为零,入队 6 } 7 while(!q.empty()){ 8 x=q.front();q.pop(); 9 a[++tot]=x; 10 for(int i=head[x];i;i=e[i].nxt){

ACM模板——拓扑排序

妖精的绣舞 提交于 2019-11-30 06:19:15
暂时 1 bool topo() 2 { 3 int count = 0 ; 4 while (!q.empty()) 5 q.pop(); 6 for (int i = 1; i <= n; i++) 7 if (!in[i]) 8 q.push(i); 9 while (!q.empty()) 10 { 11 int begin = q.front() ; 12 q.pop(); 13 count ++ ; 14 for (int i = 0; i < course[begin].size(); i ++) 15 if (--in[course[begin][i]]==0) 16 q.push(course[begin][i]) ; 17 } 18 if(count == n) 19 return true; 20 else 21 return false; 22 } 来源: https://www.cnblogs.com/Asurudo/p/11567056.html

LeetCode DFS Course Schedule 课程表 Find Eventual Safe States找到最终的安全状态

你说的曾经没有我的故事 提交于 2019-11-30 03:33:48
题目链接: 1、Course Schedule https://leetcode.com/problems/course-schedule/ 2、Find Eventual Safe States https://leetcode.com/problems/find-eventual-safe-states/ 这两题有相似性很高,区别在于第一题是判断这个图中有没有环,第二题是找出连接图中环的节点以及环上的节点 这是DFS专栏,所以暂时不考虑BFS解法 第一题其实很像拓扑排序,但是向无环图(DAG)是拓扑排序的充要条件。题目的本意是要判断是不是DAG,所以和拓扑排序还是 有点差别。(拓扑排序也有DFS和两种解法) 解法1: 使用visit数组来保存图中每一个节点的访问情况,visit[i] = 1表示 i 节点被访问了。 (本解法不适用第二题,会出现TLE) // class Solution { public: // if loop, return true bool dfs(int node,vector<int>& visit, vector<vector<int>>& graph) { if(visit[node] == 1) { return true; } visit[node] = 1; vector<int> temp = graph[node]; for(int i