第七章(9).关键路径

//与AOV网相对应的是AOE网( Activity On Edge )即边表示活动的网。AOE网是一个带权的有向无环网,其中,顶点表示事件,弧表示活动,权表示活动持续时间。
//通常AOE网可用来估算工程的完成时间!详细注释见课本!
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#include < limits.h >

#define TRUE 1  
#define FALSE 0    
#define OK 1
#define ERROR 0
#define OVERFLOW -2     

typedef int Status ;

//-------------------------图的邻接表存储表示-------------------------------//(采用邻接表表示的有向网)

#define INFINITY  INT_MAX   //最大值(无穷大)INT_MAX = 2147483647
#define MAX_VERTEX_NUM 20    //最大顶点个数(vertex顶点)
#define MAX_INFO  20    //关于边的信息的字符串长度
#define MAX_NAME  5    //关于顶点信息的字符串长度

typedef int  VRType ;    //此处考虑无权图
typedef int  InfoType ;    //如果为字符信息,则可以用char;如果为权值,则可以用int
typedef char VertexType[ MAX_NAME ]; //VertexType可以根据实际情况灵活设定类型!int,float,char…

typedef struct ArcNode{     //表结点
 int    adjvex ;   //该弧所指向的顶点的位置
 struct ArcNode *nextarc ;   //指向下一条弧的指针
 InfoType  *info ;    //该弧相关信息指针(如权值等)
} ArcNode ;

typedef struct VNode {     //表头结点
 VertexType  data ;    //顶点信息
 ArcNode   *firstarc ;   //指向第一条依附该顶点的弧的指针
} VNode , AdjList[ MAX_VERTEX_NUM ] ; 

typedef struct {
 AdjList   vertices ;
 int    vexnum , arcnum ; //图当前的顶点树和弧数
} ALGraph ;

Status InitGraph( ALGraph *G ) ;
Status LocateVex( ALGraph G , VertexType u ) ;
Status CreateGraph( ALGraph *G ) ;
Status DestroyGraph( ALGraph *G ) ;
Status Output( ALGraph G ) ;

//----------------------------------------------------------------//

#define STACK_SIZE 100
#define STACKADD 10

typedef int SElemType ;

typedef struct
{
 SElemType  *base ;   //在栈构造之前和销毁之后,base的值为NULL
 SElemType  *top ;   //栈顶指针
 int    stacksize ;     //当前已分配的储存空间,以元素为单位
} SqStack ;

Status InitStack( SqStack *S ) ;
Status Push( SqStack *S , SElemType e) ;
Status Pop( SqStack *S , SElemType *e ) ;
Status StackEmpty( SqStack S ) ;

//---------------------------------------------------------------//

SqStack T ;
int indegree[ MAX_VERTEX_NUM ] ;
int ve[ MAX_VERTEX_NUM ] ;   //ve表示时间的最早发生时间。 vl表示时间的最迟发生时间。

Status TopologicalOrder( ALGraph G , SqStack *T ) ;
Status FindInDegree( ALGraph G , int indegree[ ] ) ;
Status CriticalPath( ALGraph G ) ;

#include "head.h"

//前提为该对象为有向网。
//--------------------------------------------------------------//

Status InitGraph( ALGraph *G )   
{
 int i ;

 printf( "Please input the number of vex and arc:" ) ;
 scanf( "%d%d" , &( *G ).vexnum , &( *G ).arcnum ) ;

 printf("Input the vector of %d vex( %d char ): \n" , ( *G ).vexnum , MAX_NAME ) ;
 for( i = 0 ; i < ( *G ).vexnum ; ++ i )      //构造顶点向量,同时也初始化表头结点数组。
 {
  scanf( "%s" , ( *G ).vertices[ i ].data ) ;
  ( *G ).vertices[ i ].firstarc = NULL ;
 }

 return OK ;
}

Status LocateVex( ALGraph G , VertexType u )
{
 int k ;

 for( k = 0 ; k < G.vexnum ; ++ k )
 {
  if( strcmp( u , G.vertices[ k ].data ) == 0 )
   return k ;
 }
 return EOF ;
}

Status CreateGraph( ALGraph *G )
{
 int i ;
 int l , j ;      //定位弧头弧尾
 InfoType infor ;    //权值信息
 VertexType va , vb ;
 ArcNode *p ;

 InitGraph( G ) ;
 printf( "Please input the vexa , vexb and the weight:\n" ) ;  //权值,弧头,弧尾。

 for( i = 0 ; i < ( *G ).arcnum ; ++ i )
 {
  scanf( "%s%s%d%*c" , va , vb , &infor ) ; 

  l = LocateVex( *G , va ) ;       //弧尾 va----->vb     
  j = LocateVex( *G , vb ) ;       //弧头
  p = ( ArcNode * )malloc( sizeof( ArcNode ) ) ;  //adjvex
  p->adjvex = j ;          //Take care!
  
  p->info = ( InfoType * )malloc( sizeof( InfoType ) ) ; //切记不可丢!为指针,要用则必须申请空间。
  *( p->info ) = infor ;  

  p->nextarc = ( *G ).vertices[ l ].firstarc ;  //nextarc
  ( *G ).vertices[ l ].firstarc = p ;
 }
 return OK ;
}

Status DestroyGraph( ALGraph *G )   //释放资源和初始化
{
 int i ;
 ArcNode * p , * q ;
 
 ( *G ).arcnum = 0 ;
 ( *G ).vexnum = 0 ;

 for( i = 0 ; i < ( *G ).vexnum ; ++ i )
 {
  p = ( *G ).vertices[ i ].firstarc ;
  while( p )
  {
   q = p->nextarc ;    
   free( p->info ) ;
   free( p ) ;
   p = q ;
  } 
 }
 return OK ;
}

Status Output( ALGraph G )
{
 int i ;
 char s[ 7 ] , sa[ 4 ] ;
 ArcNode *p ;

 strcpy( s , "有向网" );
 strcpy( sa , "弧" ) ;

 printf( "\n输出含有%d顶点和%d条%s的%s:" , G.vexnum , G.arcnum , sa , s ) ;
 printf( "\nOutput the vexs:\n" ) ;   //输出顶点序列
 for( i = 0 ; i < G.vexnum ; ++ i )
 {
  printf( "G.vertices[ %d ].data = " , i ) ;
  puts( G.vertices[ i ].data ) ;   //根据VertexType而变化
 }

 printf( "\nOutput the arc:\n" ) ;   //输出弧或边
 printf( "Vex1(弧尾) Vex2(弧头) 该%s信息:\n" , sa ) ;
 for( i = 0 ; i < G.vexnum ; ++ i )   
 {
  p = G.vertices[ i ].firstarc ;
  while( p )
  {
   printf( "%s ---------- %s ---------- %d\n" , G.vertices[ i ].data , G.vertices[ p->adjvex ].data , *( p->info ) ) ;
   p = p->nextarc ;
  }  
 }
 return OK ;
}

//------------------------------------------------------------------------------//

Status InitStack(SqStack *S)
{
 S->base = (SElemType *)malloc(STACK_SIZE*sizeof(SElemType));
 if(!S->base)
 {
  exit(0);
 }
 S->top = S->base;          //look careful!  只能是s->base 赋值给s->top.
 S->stacksize = STACK_SIZE;

 return OK ;
}

Status Push(SqStack *S, SElemType e)   //把元素压入栈顶
{
 if( (S->top - S->base) >= S->stacksize )   //栈满,追加存储空间
 {
  S->base = (SElemType *)realloc(S->base, (S->stacksize + STACKADD));
 
  if(!S->base)
  {
   exit(0);
  }

  S->top = S->base + S->stacksize;
  S->stacksize += STACKADD;
 }

 *(S->top++) = e;

 return OK ;
}

Status Pop( SqStack *S , SElemType *e )   //取出栈顶元素,并返回
{
 if(S->top == S->base)
 {
  exit(0);
 }

    *e = *(--S->top);  //一定要如此,不能e = (--S->top)
 
 return OK ;   
}

Status StackEmpty(SqStack S)
{
 if( S.base == S.top )
 {
  return TRUE ;
 }

 return FALSE ;
}

//---------------------------------------------------------------------------------//

Status TopologicalOrder( ALGraph G , SqStack *T )  //有向网G采用邻接表存储结构,求各顶点时间的最早发生时间ve(全局变量)。
{              //T为拓扑序列顶点栈,S为零入度顶点栈。若G无回路,则用栈T返回G的一个拓扑序列。
 int i , j , k , count ;
 SqStack S ;
 ArcNode *p ;
 
 FindInDegree( G , indegree ) ;  //对各顶点求入度indegree[ 0 …… vexnum - 1 ]

 //建零入度顶点栈S。
 InitStack( &S ) ;
 for( i = 0 ; i < G.vexnum ; ++ i )
 {
  if( 0 == indegree[ i ] )
   Push( &S , i ) ;
 }

 //初始化拓扑序列顶点栈 用两个栈,T用于计算逆拓扑序的vl
 InitStack( T ) ;  //此处不能用InitStack( &T );  因为T本身就是一个指针.
 count = 0 ;
 for( i = 0 ; i < G.vexnum ; ++ i )
  ve[ i ] = 0 ;

 while( !StackEmpty( S ) )
 {
  Pop( &S , &j ) ;
  Push( T , j ) ;
  ++ count ;     //j号顶点入T栈并计数.

  for( p = G.vertices[ j ].firstarc ; p ; p = p->nextarc )
  {
   k = p->adjvex ;   //对j号顶点的每个邻接点的入度减1.
   if( -- indegree[ k ] == 0 )
    Push( &S , k ) ; //若入度减为0,则入栈
   
   if( ve[ j ] + *( p->info ) > ve[ k ] )
    ve[ k ] = ve[ j ] + *( p->info ) ;
  } // for *( p->info ) = dut( < j , k >)
 }   //while

 if( count < G.vexnum )
  return ERROR ;   //该有向网存在回路
 else
  return OK ;


 return OK ;
}

//对各顶点求入度indegree[ … ]
Status FindInDegree( ALGraph G , int indegree[ ] )  //相当于:int *indegree ; 呵呵……
{
 int i ;
 ArcNode *p ;

 for( i = 0 ; i < G.vexnum ; ++ i )
 {
  indegree[ i ] = 0 ;
 }

 for( i = 0 ; i < G.vexnum ; ++ i )
 {
  p = G.vertices[ i ].firstarc ;
  while( p )
  {
   indegree[ p->adjvex ] ++ ;
   p = p->nextarc ;
  }
 }
 return OK ;
}

Status CriticalPath( ALGraph G )  //G 为有向图,输出G的各项关键活动

 int i , j , k , dut , ee , el ;  //dut表示事件的持续时间。ee表示活动的最早时间,el表示活动的最迟时间。
 int vl[ MAX_VERTEX_NUM ] ;
 ArcNode *p ;

 if( !TopologicalOrder( G  , &T ) ) //Take care!此处是&T,因为此处T本身只是一个整形变量
  return ERROR ;

 j = ve[ 0 ] ;      
 for( i = 1 ; i < G.vexnum ; ++ i ) //Take care!
 {
  if( ve[ i ] > j )
   j = ve[ i ] ;
 }

 for( i = 0 ; i < G.vexnum ; ++ i ) //初始化顶点事件的最迟发生时间(最大值)
  vl[ i ] = j ;     //完成点的最早发生时间  全都赋给最大值

 while( !StackEmpty( T ) )   //按拓扑逆序列求各顶点的vl值
 {
  for( Pop( &T , &j ) , p = G.vertices[ j ].firstarc ; p ; p = p->nextarc )
  {
   k = p->adjvex ;
   dut = *( p->info ) ;  //dut< j , k >
   
   if( vl[ k ] - dut < vl[ j ] )
    vl[ j ] = vl[ k ] - dut ;
  }   //for

  printf( "The Critical Path is follow : \n" ) ;
  printf( "起点-->终点     持续时间  最早发生时间  最迟发生时间 \n" ) ;
  for( j = 0 ; j < G.vexnum ; ++ j )
   for( p = G.vertices[ j ].firstarc ; p ; p = p->nextarc )
   {
     k = p->adjvex ;
     dut = *( p->info ) ;

     ee = ve[ j ] ;
     el = vl[ k ] - dut ;
     if( ee == el )
      printf( "%3d ---> %3d  time : %2d    %d -----> %3d \n" , j , k , dut , ee , el ) ; //输出关键活动
   }
 }   //while

 return OK ;
}

 

int main( )
{
 ALGraph G ;

/* SqStack S ;
 SElemType e ;

 InitStack( &S ) ;
 Push( &S , 50 ) ;
 Pop( &S , &e ) ;
 printf( "%3d\n" , e ) ;  */

 CreateGraph( &G ) ;
 Output( G ) ;

 CriticalPath( G ) ;

 return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值