图论_关键路径



  一个下午的努力~~~~  ^_^



图论_关键路径 - Essence - ACM_Of_Essence
 

Description
        关键路径的工期决定了整个项目的工期。任何关键路径上的终端元素的延迟将直接影响项目的预期完成时间(例如在关键路径上没有浮动时间)。   
一个项目可以有多个,并行的关键路径。另一个总工期比关键路径的总工期略少的一条并行路径被称为次关键路径。   最初,关键路径方法只考虑终端元素之间的逻辑依赖关系。关键链方法中增加了资源约束。

把工程计划表示为有向图,用顶点表示事件,弧表示活动;
每个事件表示在它之前的活动已完成,在它之后的活动可以开始

AOE网

  用顶点表示事件,弧表示活动,弧上的权值表示活动持续的时间的有向图叫AOE(Activity On Edge Network)网 。AOE网常用于估算工程完成时间。例如:
   图论_关键路径 - Essence - ACM_Of_Essence

图1

图 1 是一个网。其中有9个事件v1,v2,…,v9;11项活动a1,a2,…,a11。每个事件表示在它之前的活动已经完成,在它之后的活动可以开始。如 v1表示整个工程开始,v9 表示整个工程结束。V5表示活动,a4和a5已经完成,活动a7和a8可以开始。与每个活动相联系的权表示完成该活动所需的时间。如活动a1需要6天时间 可以完成。

AOE 网具有的性质

  只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。   只有在进入某一顶点的各有向边所代表的活动都已经结束,该顶点所代表的事件才能发生。 表示实际工程计划的AOE网应该是无环的,并且存在唯一的入度过为0的开始顶点和唯一的出度为0的完成顶点。


hant
定义
AOE网(Activity On Edge)——也叫边表示活动的网。AOE网是一个带权的有向无环图,其中顶点表示事件,弧表示活动,权表示活动持续时间
路径长度——路径上各活动持续时间之和
关键路径——路径长度最长的路径叫~
Ve(j)——表示事件Vj的最早发生时间
Vl(j)——表示事件Vj的最迟发生时间
e(i)——表示活动ai的最早开始时间
l(i)——表示活动ai的最迟开始时间
l(i)-e(i)——表示完成活动ai的时间余量
关键活动——关键路径上的活动叫~,即l(i)=e(i)的活动

求关键路径步骤

求Ve(i)
求Vl(j)
求e(i)
求l(i)
计算l(i)-e(i)

算法实现
以邻接表作存储结构
从源点V1出发,令Ve[1]=0,按拓扑序列求各顶点的Ve[i]
从汇点Vn出发,令Vl[n]=Ve[n],按逆拓扑序列求其余各顶点的Vl[i]
根据各顶点的Ve和Vl值,计算每条弧的e[i]和l[i],找出e[i]=l[i]的关键活动

关键路径的几个术语
(1) 关键路径 从源点到汇点的路径长度最长的路径叫关键路径。
(2) 活动开始的最早时间e(i)   
(3) 活动开始的最晚时间l(i) 定义e(i)=l(i)的活动叫关键活动。   
(4) 事件开始的最早时间ve(i)   
(5) 事件开始的最晚时间vl(i)   
设活动ai由弧<j,k>(即从顶点j到k)表示,其持续时间记为dut(<j,k>),则   
e(i)=ve(j)   l(i)=vl(k)-dut(<j,k>) (6_6_1)   

求ve(i)和vl(j)分两步:   
· 从ve(1)=0开始向前递推  ve(j)=Max{ ve(i)+dut(<i,j>) } (6_6_2)  <i,j>T, 2<=j<=n 其中T是所有以j为弧头的弧的集合。  
· 从vl(n)=ve(n)开始向后递推  vl(i)=Min{ vl(j)-dut(<i,j>) } (6_6_3)   <i,j>S, 1<=i<=n-1  其中S是所有以i为弧尾的弧的集合。
两个递推公式是在拓扑有序和逆拓扑有序的前提下进行。  
 
求关键路径的算法  
(1) 输入e条弧<j,k>,建立AOE网的存储结构。  
(2) 从源点v1出发,令ve(1)=0,求 ve(j) 2<=j<=n。  
(3) 从汇点vn出发,令vl(n)=ve(n),求 vl(i) 1<=i<=n-1。  
(4) 根据各顶点的ve和vl值,求每条弧s(活动)的最早开始时间e(s)和最晚开始时间l(s),其中e(s)=l(s)的为关键活动。   求关键路径是在拓扑排序的前提下进行的,不能进行拓扑排序,自然也不能求关键路径。


求关键路径的算法分析

(1) 求关键路径必须在拓扑排序的前提下进行,有环图不能求关键路径;   
(2) 只有缩短关键活动的工期才有可能缩短工期;   
(3) 若一个关键活动不在所有的关键路径上,减少它并不能减少工期;   
(4) 只有在不改变关键路径的前提下,缩短关键活动才能缩短整个工期。



图论_关键路径 - Essence - ACM_Of_Essence
 

code

#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 );
}

图论_关键路径 - Essence - ACM_Of_Essence
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值