第七节 拓扑排序与关键路径.

Slides:



Advertisements
Similar presentations
因数与倍数 2 、 5 的倍数的特征
Advertisements

3 的倍数的特征 的倍数有 : 。 5 的倍数有 : 。 既是 2 的倍数又是 5 的倍数有 : 。 12 , 18 , 20 , 48 , 60 , 72 , , 25 , 60 ,
2 和 5 的倍数的特征 运动热身 怎样找一个数的倍数? 从小到大写出 2 的倍数( 10 个): 写出 5 的倍数( 6 个) 2 , 4 , 6 , 8 , 10 , 12 , 14 , 16 , 18 , 20 5 , 10 , 15 , 20 , 25 , 30.
七年级数学校本课程 台山市任远中学 李锦明. 1. 最古老的过河问题 1. 最古老的过河问题 一个农民携带一只狼,一只羊和一 箱卷心菜,要借助一条小船过河。 小船上除了农民只能再带狼、羊、 卷心菜中的一样。而农民不在时, 狼会吃羊,羊会吃菜。农民如何过 河呢?
第四单元 100 以内数的认识
第四单元 100 以内数的认识
练一练: 在数轴上画出表示下列各数的点, 并指出这些点相互间的关系: -6 , 6 , -3 , 3 , -1.5, 1.5.
2 、 5 的倍数特征 集合 2 的倍数(要求) 在百数表上依次将 2 的倍数找出 并用红色的彩笔涂上颜色。
1.2 应用举例 ( 一 ). 复习引入 B C A 1. 什么是正弦定理? 复习引入 B C A 1. 什么是正弦定理? 在一个三角形中,各边和它所对 角的正弦的比相等,即.
德 国 鼓 励 生 育 的 宣 传 画.
3.4 空间直线的方程.
第7章 网络计划技术.
常用逻辑用语复习课 李娟.
第一章 行列式 第五节 Cramer定理 设含有n 个未知量的n个方程构成的线性方程组为 (Ⅰ) 由未知数的系数组成的n阶行列式
小学生游戏.
“08高考化学学业水平(必修科目)测试的命题和教学对策研究”
勾股定理 说课人:钱丹.
初中数学八年级下册 (苏科版) 10.4 探索三角形 相似的条件(2).
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
C++程序设计 王希 图书馆三楼办公室.
江苏省2009年普通高校 招生录取办法 江苏省教育考试院
函數(一) 自訂函數、遞迴函數 綠園.
第二章 矩阵(matrix) 第8次课.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
知识点回顾 生成树、生成森林 概念、生成过程 最小生成树 概念、 MST 性质 普里姆算法和克鲁斯卡尔算法.
第七章 图 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
元素替换法 ——行列式按行(列)展开(推论)
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第3讲 C++程序控制结构 3.1 顺序结构 3.2 分支结构 3.3 循环结构 3.4 转向控制 3.5 综合案例分析.
以ISI平台为例,为您演示一下如何在Endnote文献中查看该文献的References
计算机数学基础 主讲老师: 邓辉文.
人教版数学四年级(下) 乘法分配律 单击页面即可演示.
C++语言程序设计 第二章 C++简单程序设计.
动态规划(Dynamic Programming)
使用矩阵表示 最小生成树算法.
无向树和根树.
C++大学基础教程 第3章 C++控制语句 北京科技大学 信息基础科学系.
第六节 最小生成树.
第四章 第三节 最短路径算法.
计算.
线段的有关计算.
2.6 直角三角形(二).
顺序表的删除.
作业情况 已交作业人数:140人 凡是自己没有交过作业的同学,课后留下,有话要说。 2. 文件名范例: 姓名:王树武 wshw_1.c
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
第五节 并查集.
12.2全等三角形的判定(2) 大连市第三十九中学 赵海英.
物件導向程式設計 CH2.
用计算器开方.
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第三章 程序的控制结构 第一节 概述 第二节 if选择结构 第三节 switch语句.
第九节 赋值运算符和赋值表达式.
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
3.16 枚举算法及其程序实现 ——数组的作用.
1.设A和B是集合,证明:A=B当且仅当A∩B=A∪B
树和图 tree and graph 蔡亚星.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
O x y i j O x y i j a A(x, y) y x 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算 5.4 平面向量的坐标运算.
第七、八次实验要求.
9.1.2不等式的性质 周村实验中学 许伟伟.
分数再认识三 真假带分数的练习课.
第15讲 特征值与特征向量的性质 主要内容:特征值与特征向量的性质.
4.2 图的存储结构(cont.) v1 v2 v3 v4 v5 vertex= v1 v2 v3 v4 v5 v
位似.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
RefWorks使用指南 归档、管理个人参考文献.
最小生成树 最优二叉树.
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
3.3.2 两点间的距离 山东省临沂第一中学.
Presentation transcript:

第七节 拓扑排序与关键路径

引入 AOV网 在日常生活中,一项大的工程可以看作是由若干个子工程(这些子工程称为“活动” )组成的集合,这些子工程(活动)之间必定存在一些先后关系,即某些子工程(活动)必须在其它一些子工程(活动)完成之后才能开始,我们可以用有向图来形象地表示这些子工程(活动)之间的先后关系,子工程(活动)为顶点,子工程(活动)之间的先后关系为有向边,这种有向图称为“顶点活动网络” ,又称“AOV网” 。 1 2 3 5 6 7 8 9 4

引入   在AOV网中,有向边代表子工程(活动)的先后关系,我们把一条有向边起点的活动成为终点活动的前驱活动,同理终点的活动称为起点活动的后继活动。而只有当一个活动全部的前驱全部都完成之后,这个活动才能进行。例如在上图中,只有当工程1完成之后,工程2、3、4、5、6才能开始进行。只有当2、3、4全部完成之后,7才能开始进行。   一个AOV网必定是一个有向无环图,即不应该带有回路。否则,会出现先后关系的自相矛盾。 1 2 3 4   上图就是一个出现环产生自相矛盾的情况。4是1的前驱,想完成1,必须先完成4。3是4的前驱,而2是3的前驱,1又是2的前驱。最后造成想完成1,必须先完成1本身,这显然出现了矛盾。

拓扑排序算法 拓扑排序算法,只适用于AOV网(有向无环图)。 一个AOV网的拓扑序列是不唯一的,例如下面的这张图,它的拓扑序列可以是:ABCDE,也可以是ACBDE,或是ADBCE。在下图所示的AOV网中,工程B和工程C显然可以同时进行,先后无所谓;但工程E却要等工程B、C、D都完成以后才能进行。 A B C E D 构造拓扑序列可以帮助我们合理安排一个工程的进度,由AOV网构造拓扑序列具有很高的实际应用价值。 算法思想:   构造拓扑序列的拓扑排序算法思想很简单: 选择一个入度为0的顶点并输出 然后从AOV网中删除此顶点及以此顶点为起点的所有关联边; 重复上述两步,直到不存在入度为0的顶点为止。 若输出的顶点数小于AOV网中的顶点数,则输出“有回路信息”,否则输出的顶点序列就是一种拓扑序列   从第四步可以看出,拓扑排序可以用来判断一个有向图是否有环。只有有向无环图才存在拓扑序列。

拓扑排序算法 算法实现: a) 数据结构:indgr[i]: 顶点i的入度; stack[ ]: 栈 b) 初始化:top=0 (栈顶指针置零) c) 将初始状态所有入度为0的顶点压栈 d) I=0 (计数器) e) while 栈非空(top>0) i. 栈顶的顶点v出栈;top-1; 输出v;i++; ii. for v的每一个后继顶点u 1. indgr[u]--; u的入度减1 2. if (u的入度变为0) 顶点u入栈 f) 算法结束   这个程序采用栈来找出入度为0的点,栈里的顶点,都是入度为0的点。 我们结合上图详细讲解: A B C D 开始时,只有A入度为0,A入栈。 栈:A

拓扑排序算法 栈顶元素A出栈并输出A,A的后继B、C入度减1,相当于删除A的所有关联边 B D C 拓扑序列:A 栈:空 B B、C的入度都变成0,依次将B、C入栈。 栈:BC(入栈顺序不唯一) 拓扑序列:A

拓扑排序算法 B D 栈顶元素C出栈并输出C,C的后继D入度减1 栈:B 拓扑序列:AC D 栈顶元素B出栈并输出B,B的后继D入度再减1。这时D入度为0,入栈。 栈:D 拓扑序列:ACB

拓扑排序算法 栈顶元素D出栈并输出D。栈空,结束 D 拓扑序列:ACBD(不唯一) 栈:空 简单&高效&实用的算法。上述实现方法复杂度O(V+E)。

拓扑排序算法 【例4-12】、家谱树 【问题描述】 有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。 给出每个人的孩子的信息。 输出一个序列,使得每个人的后辈都比那个人后列出。 【输入格式】 第1行一个整数N(1<=N<=100),表示家族的人数。 接下来N行,第I行描述第I个人的儿子。 每行最后是0表示描述完毕。 【输出格式】 如果有多解输出任意一解。 【输入样例】 5 4 5 1 0 1 0 5 3 0 3 0 【输出样例】 2 4 5 3 1

拓扑排序算法 【参考程序】 //gentree #include<cstdio> #include<iostream> using namespace std; int a[101][101],c[101],r[101],ans[101]; int i,j,tot,temp,num,n,m; int main() { freopen("gentree.in","r",stdin); freopen("gentree.out","w",stdout); cin >> n; for (i = 1; i <= n; i++) do cin >> j; if (j !=0 ) c[i]++; //c[i]用来存点i的出度 a[i][c[i]] = j; r[j]++; //r[i]用来存点i的入度。 } while (j != 0);

拓扑排序算法 for (i = 1; i <= n; i++) if (r[i] == 0) ans[++tot] = i; //把图中所有入度为0的点入栈,栈用一维数组ans[]表示 do { temp = ans[tot]; cout << temp << " "; tot--;num++; //栈顶元素出栈并输出 for (i = 1; i <= c[temp]; i++) r[a[temp][i]]--; if (r[a[temp][i]] == 0) //如果入度减1后变成0,则将这个后继点入栈 ans[++tot] = a[temp][i]; } while (num != n); //如果输出的点的数目num等于n,说明算法结束 return 0;

拓扑排序算法 【例4-13】奖金 【问题描述】   由于无敌的凡凡在2005年世界英俊帅气男总决选中胜出,Yali Company总经理Mr.Z心情好,决定给每位员工发奖金。公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少。于是Mr.Z下令召开m方会谈。每位参加会谈的代表提出了自己的意见:“我认为员工a的奖金应该比b高!”Mr.Z决定要找出一种奖金方案,满足各位代表的意见,且同时使得总奖金数最少。每位员工奖金最少为100元。 【输入格式】   第一行两个整数n,m,表示员工总数和代表数;以下m行,每行2个整数a,b,表示某个代表认为第a号员工奖金应该比第b号员工高。 【输出格式】   若无法找到合理方案,则输出“Poor Xed”;否则输出一个数表示最少总奖金。 【输入样例】   2 1   1 2 【输出样例】   201

拓扑排序算法 【数据规模】   80%的数据满足n<=1000,m<=2000;100%的数据满足n<=10000,m<=20000。 【算法分析】   首先构图,若存在条件“a的钱比b多”则从b引一条有向指向a;然后拓扑排序,若无法完成排序则表示问题无解(存在圈);若可以得到完整的拓扑序列,则按序列顺序进行递推: 设f[i]表示第i个人能拿的最少奖金数; 首先所有f[i]=100(题目中给定的最小值);    然后按照拓扑顺序考察每个点i,若存在有向边(j,i),则表示f[i]必须比f[j]大,因此我们令f[i] = Max { f[i] , f[j]+1 }即可; 递推完成之后所有f[i]的值也就确定了,而答案就等于f[1]+…+f[n]。

拓扑排序算法 【参考程序】 #include<iostream> using namespace std; int a[10001][301]={0},into[10001],ans[10001],m,n,money; void init() //读入数据,并构建图,统计入度 { int i,x,y; cin>>n>>m; for(i=1;i<=m;i++) { cin>>x>>y; a[y][0]++; //记录由y引出边的数目 a[y][a[y][0]]=x; //记录由a[y][0]引出边的顶点 into[x]++; //统计入度 } bool topsort() //拓扑排序 { int t,tot,k,i,j; tot=0;k=0; while(tot<n) //tot顶点个数 t=0; //用来判断有无环 for(i=1;i<=n;i++) if(into[i]==0)

拓扑排序算法 { tot++;t++;money+=100; ans[t]=i; into[i]=0xfffffff; } if(t==0)return false; //存在环 money+=k*t;k++; for(i=1;i<=t;i++) //去掉相连的边 for(j=1;j<=a[ans[i]][0];j++)into[a[ans[i]][j]]--; return true; int main() init();money=0; if(topsort())cout<<money<<endl; else cout<<"Poor Xed"<<endl; return 0;

关键路径   利用AOV网络,对其进行拓扑排序能对工程中活动的先后顺序作出安排。但一个活动的完成总需要一定的时间,为了能估算出某个活动的开始时间,找出那些影响工程完成时间的最主要的活动,我们可以利用带权的有向网,图中的边表示活动,边上的权表示完成该活动所需要的时间,一条边的两个顶点分别表示活动的开始事件和结束事件,这种用边表示活动的网络,称为“AOE网”。   其中,有两个特殊的顶点(事件),分别称为源点和汇点,源点表示整个工程的开始,通常令第一个事件(事件1)作为源点,它只有出边没有入边;汇点表示整个工程的结束,通常令最后一个事件(事件n)作为汇点,它只有入边没有出边;其余事件的编号为2到n-1。 在实际应用中,AOE网应该是没有回路的,并且存在唯一的入度为0的源点和唯一的出度为0的汇点。   下图表示一个具有12个活动的AOE网。图中有8个顶点,分别表示事件0到7,其中,0表示开始事件,7表示结束事件,边上的权表示完成该活动所需要的时间。

关键路径 AOE网络要研究的问题是完成整个工程至少需要多少时间?哪些活动是影响工程进度的关键? 下面先讨论一个事件的最早发生时间和一个活动的最早开始时间。如下图,事件Vj必须在它的所有入边活动eik(1≤k≤n)都完成后才能发生。活动eik(1≤k≤n)的最早开始时间是与它对应的起点事件Vik的最早发生时间。所有以事件Vj为起点事件的出边活动ejk(1≤k≤m)的最早开始时间都等于事件Vj的最早发生时间。所以,我们可以从源点出发按照上述方法,求出所有事件的最早发生时间。

关键路径 设数组earliest[1..n]表示所有事件的最早发生时间,则我们可以按照拓扑顺序依次计算出earliest[k]:    earliest[k]=max{earliest[j]+dut[j][k]}         (其中,事件j是事件k的直接前驱事件,dut[j][k]表示边<j,k>上的权)   对于上图,用上述方法求earliest[0..7]的过程如下: earliest[0]=0 earliest[1]=earliest[0]+dut[0][1]=0+6=6 earliest[2]=earliest[0]+dut[0][2]=0+7=7 earliest[4]=max{earliest[1]+dut[1][4],earliest[2]+dut[2][4]}     =max{6+5,7+4}     =11 earliest[3]=max{earliest[1]+dut[1][3],earliest[4]+dut[4][3]}     =max{6+3,11+3}     =14 earliest[5]=max{earliest[3]+dut[3][5],earliest[4]+dut[4][5]}     =max{14+2,11+4}     =16 earliest[6]=earliest[4]+dut[4][6]=11+3=14 earliest[7]=max{earliest[3]+dut[3][7],earliest[5]+dut[5][7], earliest[6]+dut[6][7]}     =max{14+5,16+2,14+4}     =19

关键路径 最后得到的earliest[7]就是汇点的最早发生时间,从而可知整个工程至少需要19天完成。   但是,在不影响整个工程按时完成的前提下,一些事件可以不在最早发生时间发生,而向后推迟一段时间,我们把事件最晚必须发生的时间称为该事件的最迟发生时间。同样,有些活动也可以推迟一段时间完成而不影响整个工程的完成,我们把活动最晚必须开始的时间称为该活动的最迟开始时间。一个事件在最迟发生时间内仍没发生,或一个活动在最迟开始时间内仍没开始,则必然会影响整个工程的按时完成。事件Vj的最迟发生时间应该为:它的所有直接后继事件Vjk(1≤k≤m)的最迟发生时间减去相应边<Vj,Vjk>上的权(活动ejk需要时间),取其中的最小值。且汇点的最迟发生时间就是它的最早发生时间,再按照逆拓扑顺序依次计算出所有事件的最迟发生时间,设用数组lastest[1..n]表示,即:    lastest[n]=earliest[n]    lastest[j]=min{lastest[k]-dut[j][k]}          (其中,事件k是事件j的直接后继事件,dut[j,k]表示边<j,k>上的权)   对于上图,用上述方法求lastest [0..7]的过程如下: lastest[7]=earliest[7]=19 lastest[6]=lastest[7]-dut[6][7]=19-4=15 lastest[5]=lastest[7]-dut[5][7]=19-2=17 lastest[3]=min{lastest[5]-dut[3][5],lastest[7]-dut[3][7]} =min{17-2,19-5} =14

关键路径 lastest[4]=min{lastest[3]-dut[4][3],lastest[5]-dut[4][5], lastest[6]-dut[4][6]} =min{14-3,17-4,15-3} =11 lastest[2]=lastest[4]-dut[2][4]=11-4=7 lastest[1]=min{lastest[3]-dut[1][3],lastest[4]-dut[1][4]} =min{14-3,11-5} =6 lastest[0]=min{lastest[1]-dut[0][1],lastest[2]-dut[0][2]} =min{6-6,7-7} =0 计算好每个事件的最早和最迟发生时间后,我们可以很容易地算出每个活动的最早和最迟开始时间,假设分别用actearliest和actlastest数组表示,设活动i的两端事件分别为事件j和事件k,如下所示: 活动i 事件j ————————> 事件k   则:actearliest[i]=earliest[j]     actlastest[i]=lastest[k]-dut[j][k]

关键路径 对于上图,用上述方法求得所有活动的最早和最迟开始时间如下表: <0,1> <0,2> <1,3> <1,4> <2,4> <3,5> <3,7> <4,3> <4,5> <4,6> <5,7> <6,7> 最早 6 7 14 11 16 最迟 15 13 12 17 余量 5 1 2 上表中的余量(称为开始时间余量)是该活动的最迟开始时间减去最早开始时间,余量不等于0的活动表示该活动不一定要在最早开始时间时就进行,可以拖延一定的余量时间再进行,也不会影响整个工程的完成。而余量等于0的活动必须在最早开始时间时进行,而且在规定的工期内完成,否则将影响整个工程的完成。   我们把开始时间余量为0的活动称为“关键活动”,由关键活动所形成的从源点到汇点的每一条路径称为“关键路径”。

关键路径 上图所示的AOE网的关键路径如下图所示。

上机练习 1、烦人的幻灯片 【问题描述】   李教授将于今天下午作一次非常重要的演讲。不信的事他不是一个非常爱整洁的人,他把自己演讲要用的幻灯片随便堆在了一起。因此,演讲之前他不得不去整理这些幻灯片。作为一个讲求效率的学者,他希望尽可能简单地完成它。教授这次演讲一共要用n张幻灯片(n<=26),这n张幻灯片按照演讲要使用的顺序已经用数字1~n编了号。因为幻灯片是透明的,所以我们不能一下子看清每一个数字所对应的幻灯片。   现在我们用大写字母A,B,C……再次把幻灯片依次编号。你的任务是编写一个程序,把幻灯片的数字编号和字母编号对应起来,显然这种对应应该是唯一的;若出现多种对应的情况或是某些数字编号和字母编号对应不起来,我们称对应是无法实现的。 【输入格式】   文件的第一行只有一个整数n,表示有n张幻灯片,接下来的n行每行包括4个整数xmin,xmax,ymin,ymax(整数之间用空格分开)为幻灯片的坐标,这n张幻灯片按其在文件中出现的顺序从前到后依次编号为A,B,C……,再接下来的n行依次为n个数字编号的坐标x,y,显然在幻灯片之外是不会有数字的。 【输出格式】   若是对应可以实现,输出文件应该包括n行,每一行为一个字母和一个数字,中间以一个空格隔开,并且每行以字母的升序排列,注意输出的字母要大写并且定格;反之,若是对应无法实现,在文件的第一行顶格输出None即可。首行末无多余的空格。 【输入输出样例】 slides.in slides.out 4 6 22 10 20 4 18 6 16 8 20 2 18 10 24 4 8 9 15 19 17 11 7 21 11 A 4 B 1 C 2 D 3

上机练习 2、病毒 【问题描述】   有一天,小y突然发现自己的计算机感染了一种病毒!还好,小y发现这种病毒很弱,只是会把文档中的所有字母替换成其它字母,但并不改变顺序,也不会增加和删除字母。   现在怎么恢复原来的文档呢!小y很聪明,他在其他没有感染病毒的机器上,生成了一个由若干单词构成的字典,字典中的单词是按照字母顺序排列的,他把这个文件拷贝到自己的机器里,故意让它感染上病毒,他想利用这个字典文件原来的有序性,找到病毒替换字母的规律,再用来恢复其它文档。   现在你的任务是:告诉你被病毒感染了的字典,要你恢复一个字母串。 【输入格式】virus.in   第一行为整数K(≤50000),表示字典中的单词个数。   以下K行,是被病毒感染了的字典,每行一个单词。   最后一行是需要你恢复的一串字母。   所有字母均为小写。 【输出格式】virus.out    输出仅一行,为恢复后的一串字母。当然也有可能出现字典不完整、甚至字典是错的情况,这时请输出一个0。

上机练习 【输入样例】   6   cebdbac   cac   ecd   dca   aba   bac   cedab 【输出样例】   abcde