#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include"ALGraph.h"
#include"sqstack.h"
void FindInDegree(ALGraph G,int indegree[]); // 求顶点的入度
int TopologicalOrder(ALGraph G,SqStack &T); // 有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve(全局变量),若G无回路,则用栈T返回G的一个拓扑序列,且函数值为1,否则为0
int CriticalPath(ALGraph G); // G为有向网,输出G的各项关键活动 int ve[MAX_VERTEX_NUM];
int ve[MAX_VERTEX_NUM]; //求各顶点事件的最早发生时间ve(全局变量)
int main()
{
ALGraph g;
//printf("请创建有向网\n");
CreateGraphF(g); // 构造有向网
Display(g); // 输出有向网
CriticalPath(g); // 求g的关键路径
return 0;
}
void FindInDegree(ALGraph G,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->data.adjvex]++;
p=p->nextarc;
}
}
}
int TopologicalOrder(ALGraph G,SqStack &T)
{ // 有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve(全局变量)。T为拓扑序列
// 顶点栈,S为零入度顶点栈。若G无回路,则用栈T返回G的一个拓扑序列,且函数值为1,否则为0
int i,k,count=0; // 已入栈顶点数,初值为0
int indegree[MAX_VERTEX_NUM]; // 入度数组,存放各顶点当前入度数
SqStack S;
ArcNode *p;
FindInDegree(G,indegree); // 对各顶点求入度indegree[]
InitStack(S); // 初始化零入度顶点栈S
printf("拓扑序列:");
for(i=0;i<G.vexnum;++i) // 对所有顶点i
if(!indegree[i]) // 若其入度为0
Push(S,i); // 将i入零入度顶点栈S
InitStack(T); // 初始化拓扑序列顶点栈
for(i=0;i<G.vexnum;++i) // 初始化ve[]=0(最小值,先假定每个事件都不受其他事件约束)
ve[i]=0;
while(!StackEmpty(S)) // 当零入度顶点栈S不空
{
Pop(S,i); // 从栈S将已拓扑排序的顶点j弹出
printf("%s ",G.vertices[i].data);
Push(T,i); // j号顶点入逆拓扑排序栈T(栈底元素为拓扑排序的第1个元素)
++count; // 对入栈T的顶点计数
for(p=G.vertices[i].firstarc;p;p=p->nextarc)
{ // 对i号顶点的每个邻接点
k=p->data.adjvex; // 其序号为k
if(--indegree[k]==0) // k的入度减1,若减为0,则将k入栈S
Push(S,k);
if(ve[i]+(p->data.info)>ve[k]) // (p->data.info)是<i,k>的权值
ve[k]=ve[i]+(p->data.info); // 顶点k事件的最早发生时间要受其直接前驱顶点i事件的
} // 最早发生时间和<i,k>的权值约束。由于i已拓扑有序,故ve[i]不再改变
}
if(count<G.vexnum)
{
printf("此有向网有回路\n");
return 0;
}
else
return 1;
}
int CriticalPath(ALGraph G)
{
// G为有向网,输出G的各项关键活动
/********** Begin **********/
int vl[MAX_VERTEX_NUM]; // 事件最迟发生时间
SqStack T;
int i,j,k,ee,el,dut;
ArcNode *p;
if(!TopologicalOrder(G,T)) // 产生有向环
return 0;
j=ve[0]; // j的初值
for(i=1;i<G.vexnum;i++)
if(ve[i]>j)
j=ve[i]; // j=Max(ve[]) 完成点的最早发生时间
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)
{
// 弹出栈T的元素,赋给j,p指向j的后继事件k,事件k的最迟发生时间已确定(因为是逆拓扑排序)
k=p->data.adjvex;
dut=(p->data.info); // dut=<j,k>的权值
if(vl[k]-dut<vl[j])
vl[j]=vl[k]-dut; // 事件j的最迟发生时间要受其直接后继事件k的最迟发生时间
} // 和<j,k>的权值约束。由于k已逆拓扑有序,故vl[k]不再改变
printf("\ni\tve[i]\tvl[i]\n");
for(i=0;i<G.vexnum;i++) // 初始化顶点事件的最迟发生时间
{
printf("%d\t%d\t%d\t",i,ve[i],vl[i]);
if(ve[i]==vl[i])
printf(" 关键路径经过的顶点");
printf("\n");
}
printf("j\tk\t权值\tee\tel\n");
for(j=0;j<G.vexnum;++j) // 求ee,el和关键活动
for(p=G.vertices[j].firstarc;p;p=p->nextarc)
{
k=p->data.adjvex;
dut=(p->data.info); // dut=<j,k>的权值
ee=ve[j]; // ee=活动<j,k>的最早开始时间(在j点)
el=vl[k]-dut; // el=活动<j,k>的最迟开始时间(在j点)
printf("%s→\t%s\t%d\t%d\t%d\t",G.vertices[j].data,G.vertices[k].data,dut,ee,el);
// 输出各边的参数
if(ee==el) // 是关键活动
printf("关键活动");
printf("\n");
}
return 1;
/********** End **********/
}