拓扑排序

预备知识

​   一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity)。在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
  一个AOV网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行。这种情况若在程序中出现,则称为死锁或死循环,是必须避免的。
  在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。
  由AOV网构造出拓扑序列的实际意义是:如果按照拓扑序列中的顶点次序,在开始每一项活动时,能够保证它的所有前驱活动都已完成,从而使整个工程顺序进行,不会出现冲突的情况。

定义

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

  

#641. 拓扑排序

小数在前大数在后——维护一个入度为0的小顶堆顶点集合
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>using namespace std;#define N 2000
#define M 400000int head[N + 5], edg[M + 5], nxt[M + 5], tot;
int in_degree[N + 5];void add(int s, int e) {++in_degree[e];++tot;edg[tot] = e;nxt[tot] = head[s];head[s] = tot;return ;
}priority_queue<int, vector<int>, greater<int> > que;int main() {int n, m;cin >> n >> m;for (int i = 1, s, e; i <= m; ++i) {cin >> s >> e;add(s, e);}for (int i = 1; i <= n; ++i) {if (in_degree[i] == 0)  que.push(i);}while (!que.empty()) {int t = que.top();que.pop();cout << t;for (int i = head[t]; i; i = nxt[i]) {--in_degree[edg[i]];if (in_degree[edg[i]] == 0)  que.push(edg[i]);}if (!que.empty())  cout << " ";}cout << endl;return 0;
}

  
  

#640. 食物链计数

初始入度为0点贡献为1,每个顶点的贡献为其所有前驱点贡献的和
答案累加所有出度为0的点的贡献(食物链终端)(无后继的点)
拓扑排序算法会遍历所有边所有点!!!
#include <iostream>
#include <cstdio>
#include <stack>using namespace std;const int N = 5e3;
const int M = 5e5;
const int P = 1e8 + 7;int head[N + 5], edg[M + 5], nxt[M + 5], tot;
int in_degree[N + 5], sum[N + 5];void add(int s, int e) {++in_degree[e];++tot;edg[tot] = e;nxt[tot] = head[s];head[s] = tot;return ;
}int main() {int n, m, ans = 0;scanf("%d%d", &n, &m);for (int i = 1, s, e; i <= m; ++i) {scanf("%d%d", &s, &e);add(s, e);}stack<int> s;for (int i = 1; i <= n; ++i) {if (in_degree[i])  continue;sum[i] = 1;s.push(i);}while (!s.empty()) {int t = s.top();s.pop();if (!head[t]) {ans = (ans + sum[t]) % P;continue;}for (int i = head[t]; i; i = nxt[i]) {--in_degree[edg[i]];sum[edg[i]] = (sum[edg[i]] + sum[t]) % P;if (in_degree[edg[i]] == 0) {s.push(edg[i]);}}}printf("%d\n", ans);return 0;
}

  
  

#636. 旅行计划

ans[i] : 以i点作为终点,最多可以走多少城市
初始时,入度为0的点ans为1, 之后其它点的ans为其所有前驱节点最大的ans + 1
一旦某点的入度为0时,其ans为最终答案,因为所有前驱节点均已遍历
#include <iostream>
#include <cstdio>
#include <stack>using namespace std;const int N = 1e5;
const int M = 2e5;int head[N + 5], edg[M + 5], nxt[M + 5], tot;
int in_degree[N + 5], ans[N + 5];void add(int s, int e) {++in_degree[e];++tot;edg[tot] = e;nxt[tot] = head[s];head[s] = tot;return ;
}int main() {int n, m;scanf("%d%d", &n, &m);for (int i = 1, s, e; i <= m; ++i) {scanf("%d%d", &s, &e);add(s, e);}stack<int> s;for (int i = 1; i <= n; ++i) {if (in_degree[i])  continue;ans[i] = 1;s.push(i);}while (!s.empty()) {int t = s.top();s.pop();for (int i = head[t]; i; i = nxt[i]) {--in_degree[edg[i]];ans[edg[i]] = max(ans[edg[i]], ans[t] + 1);if (in_degree[edg[i]] == 0) {s.push(edg[i]);}}}for (int i = 1; i <= n; ++i) {printf("%d\n", ans[i]);}return 0;
}

  
  

#637. 排序

每插入一条边就进行一次拓扑排序,注意每次都要拷贝出一份临时的入度数组
并且每插入一组点要统计此时图中的点数cnt,并且初始状态所有点的入度应为-1封装一个拓扑排序函数,返回值为拓扑序是否唯一(如果度为0的点始终为1个,则序列唯一)输出优先级:
1、如果存在环  (拓扑序列长度 < cnt)
2、如果可以确定序列  (n <= cnt && 序列唯一)
3、最后一条边插入后也没有满足前两个条件 (最终无法确定唯一序列)
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <stack>using namespace std;const int N = 128;
const int M = 1e4;int head[N + 5], edg[M + 5], nxt[M + 5], tot;
int flag[N + 5], cnt, __in_degree[N + 5];void add(int s, int e) {if (flag[s] == 0)  flag[s] = 1, ++cnt;if (flag[e] == 0)  flag[e] = 1, ++cnt;if (__in_degree[s] == -1)  __in_degree[s] = 0;if (__in_degree[e] == -1)  __in_degree[e] = 0;++__in_degree[e];++tot;edg[tot] = e;nxt[tot] = head[s];head[s] = tot;return ;
}string topo_str;bool topo_sort() {vector<int> in_degree(__in_degree, __in_degree + N + 5);bool only = true;topo_str = "";stack<int> s;for (char i = 'A'; i <= 'Z'; ++i) {if (in_degree[i] == 0)  s.push(i);}while (!s.empty()) {if (s.size() - 1)  only = false;int t = s.top();s.pop();topo_str += ((char)t);for (int i = head[t]; i; i = nxt[i]) {--in_degree[edg[i]];if (in_degree[edg[i]] == 0)  s.push(edg[i]);}}return only;
}int main() {memset(__in_degree, -1, sizeof(__in_degree));int n, m;scanf("%d%d", &n, &m);char str[5];for (int i = 1; i <= m; ++i) {scanf("%s", str);add(str[0], str[2]);bool is = topo_sort();if ((int)topo_str.size() < cnt) {printf("Inconsistency found after %d relations.\n", i);return 0;}if (is && (int)topo_str.size() >= n) {printf("Sorted sequence determined after %d relations: %s.\n", i, topo_str.c_str());return 0;}}printf("Sorted sequence cannot be determined.\n");return 0;
}

拓扑排序(topo_sort)相关推荐

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

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

  2. 拓扑排序Kahn算法

    拓扑排序 介绍 思路 操作过程 完美图解 代码模板 介绍 拓扑排序,整体是给出n个事件先后关系,来确定n个事件最终的先后关系 思路 很好理解 操作过程 我们可以理解成一个有向图如果x事件在y事件的前面 ...

  3. HDU-5222 Exploration(拓扑排序)

    一.题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5222 二.题意 给一个无向边+有向边的混合图,其中每条边只能使用一次,问图中是否存在环. 三.思路 ...

  4. 【CodeForces 1100E】二分答案 | 拓扑排序 | E

    这是一道很美妙的题- 1100E. Andrew and Taxi time limit per test: 2 seconds memory limit per test: 256 megabyte ...

  5. 图论---拓扑排序的应用

    最近研究了几道图论的题目,都是图论入门的算法,用的比较多的就是拓扑排序,多用于有着先后顺序的题目,也可以用来判断环,做个小总结. 杂物 题目链接:杂务 - 洛谷 这一题需要计算最短的时间,利用了记忆化 ...

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

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

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

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

  8. hdu 5438 Ponds 拓扑排序

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

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

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

最新文章

  1. c语言 python-C语言、Java语言和python语言的区别在哪里
  2. pythonc语言结构_C语言结构体笔记
  3. 最短路径之--floyd算法--多源最短路径
  4. iOS 删除、重新排序xcdatamodel
  5. P4700-[CEOI2011]Traffic【tarjan,dp】
  6. [MEGA DEAL] Ultimate SQL Bootcamp认证捆绑包(98%)
  7. java 18 - 6 TreeMap嵌套使用
  8. 38. 统计一个整数的二进制表示中bit为1的个数
  9. XDOJ-1002-小W的塔防(dp)
  10. [转]使用debugger调试JavaScript脚本
  11. python-三层神经网络的分类回归问题
  12. 【转】flex中的labelFunction(combox和dataGrid)
  13. Markdown自定义CSS样式
  14. 虚拟机上安装win7系统
  15. Android平台语言支持状态(MTK6589)
  16. asterisk注册河南联通ims
  17. 在yii2应用中,使用imagine库生成分享图实战。
  18. 进制转换--(2-8)为什么2的3次方=8,所以三位变一位
  19. MATLAB人脸检测系统
  20. Eclipse 常用快捷键整理

热门文章

  1. c++编程简易计算器、JavaScript游戏
  2. HDMI 之 HPD
  3. 《黑马程序员》 正则的匹配 切割 替换 获取的操作演示
  4. This beta version of Typora is expired, please download and install a newer version.
  5. linux用命令开触摸板,centos 6 linux下禁用触摸板(通过命令行实现)
  6. java mac转unix_管理Java类路径(UNIX和Mac OS X)
  7. 值得反复研读的表连接之CARTESIAN JOIN方式
  8. SVL - 共享VLAN学习模式
  9. html5快速制作,html5动画制作(教你如何快速绘制HTML5动画)
  10. How to manually generate ssl certificate for own site in Linux