关键路径的相关知识
来源:互联网 发布:java判断字符串为空格 编辑:程序博客网 时间:2024/06/03 13:15
一 基本概念
关键路径是对数据结构中图的又一大应用。
1、AOE网的概念:在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,边上的权值表示活动的持续时间,称这样的有向图叫做边表示活动的网,简称AOE网。AOE网中没有入边的顶点称为始点(或源点),没有出边的顶点称为终点(或汇点)。
2、关键路径的概念:从始点到终点的路径长度最大的路径即为关键路径。关键路径上的活动为关键活动。
3、所用到的几个参量定义:
(1)事件Vk的最早发生时间,用ve(k)表示
指从顶点V到Vk的最长路径长度,事件的最早发生时间决定了所有从Vk开始的活动能够开工的最早时间。ve(k)=Max{ve(j)+weight(Vj,Vk)}
(2)事件Vk的最晚发生时间,用vl(k)表示
指在不推迟工期的情况下,保证它指向的事件Vi在ve(i)时刻发生时,该事件最迟发生的时间。vl(j)=Min{(vl(k)-weight(Vj,Vk)}
(3)活动Ak的最早开始时间,用e(i)表示,e(i)=ve(k)
指该活动的起点所表示的最早的开始时间。
(4)活动Ak的最迟开始时间,用l(i)表示,l(i)=vl(j)-weight(Vk,Vj)
指该活动的终点所表示的事件最迟发生时间与该活动所需时间之差。
二 举例
例如:
V1
V2
V3
V4
V5
V6
ve(k),事件最早开始时间
0
3
2
6
6
8
vl(k),事件最晚开始时间
0
4
2
6
7
8
上表中V2最晚开始时间有多个,取最小值即可。
A1
A2
A3
A4
A5
A6
A7
A8
E(i),活动最早开始时间
0
0
3
3
2
2
6
6
A1
A2
A3
A4
A5
A6
A7
A8
l(i),活动最迟开始时间
1
0
4
4
2
5
6
7
E(i)=l(i),即为关键活动。所以关键活动是:A2、A5、A7
下面用C语言来实现:(代码来自:http://luojilie.blog.163.com/blog/static/19182696320117125832393/)
#include <stdio.h>
#include <malloc.h>
#define M 20
#define MAX 100
typedef struct node
{ int vex;
int length;
struct node *next;
}JD;
typedef struct tnode
{ int vexdata;
int in;
struct node *link;
}TD;
int loc_vertex(TD g[],int vex,int n) //定位输入结点的存储坐标
{ int i,j;
for(i=1;i<=n;i++)
if(g[i].vexdata==vex)
return(i);
return(0);
}
int crt_linklist(TD g[]) //建立邻接链表
{ int n,e,i,j,k,vt,vh,length;
JD *p;
printf("Input and the number of node,arc:");
scanf("%d,%d",&n,&e);
for(i=1;i<=n;i++) //输入结点的信息
{ printf("g[%d].vexdata=",i);
scanf("%d",&g[i].vexdata);
g[i].in=0;
g[i].link=NULL;
}
for(k=1;k<=e;k++) //输入边的信息
{ printf("Vt,Vh,length:");
scanf("%d,%d,%d",&vt,&vh,&length);
i=loc_vertex(g,vt,n);
j=loc_vertex(g,vh,n);
p=(JD *)malloc(sizeof(JD));
p->vex=j;
p->length=length;
p->next=g[i].link;
g[i].link=p;
}
return(n);
}
void cal_in(TD g[],int n) //计算每个结点的入度
{ int i,k;
JD *p;
for(i=1;i<=n;i++)
{ p=g[i].link;
while(p!=NULL)
{ k=p->vex;
g[k].in++;
p=p->next;
}
}
}
int dut(TD g[],int vt,int vh) //返回每个结点之间的边的权值
{ JD *p;
p=g[vt].link;
while(p!=NULL)
{ if(p->vex==vh)
return(p->length);
else
p=p->next;
}
return(MAX);
}
int toporder(TD g[],int n,int ve[],int top2[],int *t2) //作用在于求ve[k],和为后面的求vl[k]
{ int top1[M];
int m,k,j,top;
JD *p;
top=0; m=0;
for(j=1;j<=n;j++) //初始化事件(结点)的最早开始时间,方法二:memset(ve,0,sizeof(ve));
ve[j]=0;
for(j=1;j<=n;j++)
if(g[j].in==0)
{ top1[top]=j;
top++;
}
while(top>0)
{ j=top1[--top];
top2[*t2]=j; //t2初值为零
(*t2)++;
m++;
p=g[j].link;
while(p!=NULL)
{ k=p->vex;
g[k].in--;
if(g[k].in==0)
top1[top++]=k;
if(ve[j]+dut(g,j,k)>ve[k]) //求ve[k],ve[k]=ve[j]+dut(g,j,k);(ve[1]=0;)
ve[k]=ve[j]+dut(g,j,k);
p=p->next;
}
}
if(m<n) return(0);
else return(1);
}
void critical_path(TD g[],int n)
{ int i,t2=0,j,k,ee,el;
char tag;
JD *p;
int ve[M],vl[M],top2[M];
i=toporder(g,n,ve,top2,&t2);
if(!i)
printf("Has a cycle!");
else
{ for(i=1;i<=n;i++)
vl[i]=MAX;
///* 求出vl[k]*///
vl[n]=ve[n];
while(t2>0)
{ j=top2[--t2];
p=g[j].link;
while(p!=NULL)
{ k=p->vex;
if(vl[k]-dut(g,j,k)<vl[j])
vl[j]=vl[k]-dut(g,j,k);
p=p->next;
}
}
///* 求出活动的的e[k],l[k]*///
for(j=1;j<=n;j++)
{ p=g[j].link;
while(p!=NULL)
{ k=p->vex;
ee=ve[j];
el=vl[k]-dut(g,j,k);
if(ee==el)
tag='*';//表示关键路径
else
tag=' ';
printf("Vt=%d,Vh=%d,Length=%d,ee=%d,el=%d,%c\n",j,k,dut(g,j,k),ee,el,tag);
p=p->next;
}
}
}
}
int main()
{ int n;
TD g[M];
n=crt_linklist(g);
cal_in(g,n);
critical_path(g,n);
return (0);
}
- 关键路径的相关知识
- 关键路径的选取
- 图的关键路径
- 关键路径的实现
- 图的关键路径
- 图的关键路径
- 图的关键路径
- 关键路径的计算
- 图的关键路径
- 图的关键路径
- 图的关键路径
- C#路径设置相关知识
- 欧拉路径相关知识
- Hibernate的一些关键知识
- 图的关键路径算法
- AOE图的关键路径
- AOE网上的关键路径
- 求图的关键路径
- 多线程面试题
- 3.第一个Java程序HelloWorld
- Mongodb 利用mongoshell进行数据类型转换
- Maven聚合与继承
- 文件下载
- 关键路径的相关知识
- LeetCode by Java. binary-tree-preorder-traversal
- cifar数据库及图像可视化
- Android M Permission 运行时权限
- Android:使用自定义keystore的方法及注意事项
- NIO学习(二) buffer
- 实时故障树
- oracle存储过程转mysql存储过程修改方法
- 二叉树遍历