//与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 -2typedef 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 10typedef 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 >)
} //whileif( 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 ;
} //forprintf( "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 ) ; //输出关键活动
}
} //whilereturn 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 ;
}
第七章(9).关键路径
最新推荐文章于 2022-11-06 17:47:27 发布