您的位置:首页 > 其它

拓扑排序和关键路径分析

2018-03-13 23:19 197 查看
肛了小一天的《离散数学》和《算法导论》,希望能深入浅出的说明这个本来就很简单的问题
拓扑排序是一个比较神奇的东西。
下面给出它的定义:
在集合论中它的定义是:构造一个包含某个给定偏序的全序的过程称为拓扑排序。(见《离散数学》P41)
在图论中的定义是:对于一个有向无环图G = (V,E),对于某条边(u,v)属于G ,则结点u在拓扑排序中处于结点v的前面。(见《算法导论》P355)
是不是有一点晦涩难懂呢?哈哈,找张图来说明吧

(谁画的图,好丑啊)
在这张图中,我们可以知道1->2,1->3,2->4,3->4;但是,2和3之间的关系怎么确定呢?简单啊,自己加一条边呗(嘿嘿嘿)2->3,3->2都可以,喜欢那个用哪个以 2->3为例 加上一条边之后,就成了这个样子:


之后 这个图就可以写成 1->2->3->4 了;当然 因为加边的过程是任意的,你也可以写成 1->3->2->4;这就是拓扑排序是不是很简单呢?个人理解:拓扑排序的意义就在于在一个有向图中,找出一个顺序,可以在有向图中,依次遍历各个点。那我们应该怎么实现拓扑排序呢?也很简单,首先,我们需要找到这个图中的“头”,也就是在图中,只向外指的点。例如图中的“1”,他就是这个图中的“头”;我们把1记录下来,然后砍掉他


现在出现了两个“头”,怎么办呢?随便砍一个吧!


砍了2之后,接下来的操作,想必你已经会了吧!接着砍砍砍……直到没有头可砍,我们的任务就完成了。如果觉得已经掌握这种算法了那我就来介绍一个拓扑排序的应用——关键路径分析法(看离散知道的233)大家可以想一下起床的过程——起床,穿衣,穿裤子,穿袜子,刷牙洗脸,煮饭,吃饭,出门。有些事情的顺序是不能变的,比方说,我不能没穿衣服就出门;但有一些顺序是可变的,比如煮饭可以先于刷牙洗脸,而且他们可以同时进行,这样会大大节省时间;但是,不管我再怎么节省时间,时间还是在流逝。我要找我总共需要花费多少时间以及找出我为什么要花这么多时间(即找出一条关键路径来刻画我完成这些流程所需时间的过程)
在这里贴一道关键路径分析的经典题:hdu 4109(鶸用来一种很傻缺的思路写这个题,实在是太丑了233)#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

queue<int> cost[1005];//存时间消耗
queue<int> son[1005];//存儿子
queue<int> H; //存头
int h[1005],e[1005];
int ans[1005];
int main() {
int n,m;
while(cin >> n >> m) {
for (int i = 0; i < n; i++) {
cost[i] = son[i] = queue<int>();
h[i] = e[i] = ans[i] = 0;
}
while(m--) {
int x,y,z;
cin >> x >> y >> z;
h[y]++;
e[x] = 1;
son[x].push(y);
cost[x].push(z);
}
for (int i = 0; i < n; i++) {
if(!h[i]) {
H.push(i);
ans[i] = 1;
}
}
while(!H.empty()) {
int tmp = H.front();
while(!son[tmp].empty()) {
int tmp1 = son[tmp].front();
ans[tmp1] = max(ans[tmp1],cost[tmp].front() + ans[tmp]);
h[tmp1]--;
if(!h[tmp1])
H.push(tmp1);
son[tmp].pop();
cost[tmp].pop();
}
H.pop();
}
int Max = 0;
for (int i = 0; i < n; i++) {
if(!e[i]) {
Max = max(Max,ans[i]);
}
}
cout << Max <<endl;
}
return 0;
}
/*
10 11
0 2 4
1 2 3
2 3 5
2 4 4
2 6 4
3 5 3
4 5 3
6 7 2
5 8 6
7 9 11
8 9 3
要是wa了就试一试这一组数据吧
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: