/*adjlist.h有向无环图的邻接表存储结构*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_VERTEX_NUM 10
#define MAX_NAME 10
typedef char VertexData[MAX_NAME];
typedef struct ArcNode
{
int adjvex;
int weight;
struct ArcNode *nextarc;
}ArcNode;
typedef struct VertexNode
{
VertexData data;
ArcNode *firstarc;
}VertexNode;
typedef struct
{
VertexNode vertex[MAX_VERTEX_NUM];
int vertexnum,arcnum;
}AdjList;
void Visit(char *s)
{
printf("%s",s);
}
int LocateVertex(AdjList *G,VertexData u)
{
int i;
for(i=0;i<G->vertexnum;i++)
if(!strcmp(u,(*G).vertex[i].data))
return i;
return -1;
}
void CreateGraph(AdjList *G)
{
int i;
int head,tail;
VertexData vh,vt;
ArcNode *p=NULL,*pnew=NULL;
printf("请输入有向无环图的顶点数,边数(以逗号隔开):");
scanf("%d,%d",&G->vertexnum,&G->arcnum);
for(i=0;i<G->vertexnum;i++)
{
printf("请输入%d个顶点(工程事件): \n",i+1);
scanf("%s",(*G).vertex[i].data);
(*G).vertex[i].firstarc=NULL;
}
for(i=0;i<G->arcnum;i++)
{
printf("输入第%d个活动的弧头: ",i+1);
scanf("%s",vh);
printf("输入第%d个活动的弧尾:",i+1);
scanf("%s",vt);
head=LocateVertex(G,vh);
tail=LocateVertex(G,vt);
pnew=(ArcNode *)malloc(sizeof(ArcNode));
pnew->adjvex=head;
pnew->nextarc=NULL;
printf("请输入这个活动的时间: ");
scanf("%d",&(pnew->weight));
putchar('\n');
p=(*G).vertex[tail].firstarc;
if(p==NULL)
(*G).vertex[tail].firstarc=pnew;
else
{
while(p->nextarc!=NULL)
p=p->nextarc;
p->nextarc=pnew;
}
}
}
/*stack.h栈的存储结构*/
#define MAX_STACK_NUM MAX_VERTEX_NUM+1
typedef struct
{
int stack[MAX_STACK_NUM];
int top;
}Stack;
void InitStack(Stack *S)
{
S->top=-1;
}
bool StackEmpty(Stack *S)
{
if(S->top<0)
return true;
else
return false;
}
bool IsFull(Stack *S)
{
if(S->top>MAX_VERTEX_NUM)
return true;
else
return false;
}
bool Push(Stack *S,int in)
{
S->top++;
if(IsFull(S))
{
fprintf(stderr,"栈满");
return false;
}
S->stack[S->top]=in;
return true;
}
bool Pop(Stack *S,int *out)
{
if(StackEmpty(S))
{
fprintf(stderr,"栈空\n");
return false;
}
*out=S->stack[S->top--];
return true;
}
/*main.c驱动程序*/
#include"adjlist.h"
#include"stack.h"
int indegree[MAX_VERTEX_NUM];
int ve[MAX_VERTEX_NUM]; //各顶点事件的最早发生时间
int vl[MAX_VERTEX_NUM]; //各顶点事件的最迟发生时间
void FindIndegree(AdjList *G)
{
int i,k;
ArcNode *p;
for(i=0;i<G->vertexnum;i++)
for(p=G->vertex[i].firstarc;p;p=p->nextarc)
{
k=p->adjvex;
indegree[k]++;
}
}
bool TopologicalOrder(AdjList *G,Stack *T)
{
int i,j,k;
int count=0;//用来对输出的拓扑序列进行计数
ArcNode *p=NULL;//用来将每次以出栈顶点为弧尾的弧删除的辅助指针
Stack S;//S为0入度顶点栈
memset(indegree,0,sizeof(indegree));
memset(ve,0,sizeof(ve)); //初始化顶点事件 最早发生时间
FindIndegree(G);
InitStack(&S);
/*接下来让所有入度为0的顶点入栈*/
for(i=0;i<G->vertexnum;i++)
if(!indegree[i])
Push(&S,i);
InitStack(T);
printf("\n拓扑序列是: ");
while(!StackEmpty(&S))
{
Pop(&S,&j);
Push(T,j);
++count; //j号顶点入T栈并计数
printf("%s ",G->vertex[j].data);
for(p=G->vertex[j].firstarc;p;p=p->nextarc)
{
k=p->adjvex;
if(!(--indegree[k]))
Push(&S,k); //若k顶点入度为0则入0度顶点栈S
if(ve[j]+p->weight > ve[k])
ve[k]=ve[j]+p->weight;//这条if语句求以k为弧头的顶点的最早发生时间
}
}
if(count<G->vertexnum) //该有向图有回路
return false;
return true;
}
bool CriticalPath(AdjList *G)
{
int i,j,k;
int dut; //记录活动时间
int ee,el; //ee代表活动的最早开始时间,el代表活动的最迟开始时间
ArcNode *p;
Stack T; //栈T是拓扑序列栈
if(TopologicalOrder(G,&T))
printf("\n工程能顺利完工\n");
else
{
printf("\n工程无法顺利完工\n");
return false;
}
for(i=0;i<G->vertexnum;i++)//初始化顶点事件 最迟发生时间
vl[i]=ve[G->vertexnum-1];
/*接下来按拓扑逆序求个顶点的vl值*/
while(!StackEmpty(&T))
{
Pop(&T,&j);
for(p=G->vertex[j].firstarc;p;p=p->nextarc)
{
k=p->adjvex;
dut=p->weight;
if(vl[k] - dut < vl[j])
vl[j]=vl[k] -dut;
}
}
/*到此处为止已经求出了给个顶点的ve和vl值了最后要求关键活动只要
比较弧的ee和el值如果相等就代表该弧所代表的就是关键活动*/
printf("该工程的关键活动是:\n");
for(i=0;i<G->vertexnum;i++)
for(p=G->vertex[i].firstarc;p;p=p->nextarc)
{
k=p->adjvex;
dut=p->weight;
ee=ve[i];
el=vl[k]-dut;
if(ee==el)
printf("\t从%s到%s所经时间\n",G->vertex[i].data,G->vertex[k].data);
}
return true;
}
int main(void)
{
AdjList G;
// freopen("text.txt","r",stdin);
CreateGraph(&G);
if(CriticalPath(&G))
printf("最短工期为%d\n",ve[G.vertexnum-1]);
// fclose(stdin);
}