typedef struct arcnode
{
int weight;//权重
int adjvex;//指向的下一个顶点
struct arcnode *next;//指向这个点的另一条边
}Arcnode,*pArcnode;
typedef struct vnode
{
pArcnode firstarc;//点所指向的第一条边
}Vnode,AdjList[30];
typedef struct graph
{
int Vnum,Arcnum;//点的数目,边的数目
AdjList vertice;
}Graph,*pGraph;
void CreateGraph(pGraph G)//构造AOE网
{
int i;
int node1,node2,weight;//暂时存储数据
pArcnode p1;
printf("请输入有向图的总点数:\n");
scanf("%d",&G->Vnum);
getchar();
for(i=0;i<G->Vnum;i++)//给每个结点的第一个后继边初始化
{
G->vertice[i].firstarc=NULL;
}
printf("请输入无向图的总边数:\n");
scanf("%d",&G->Arcnum);
getchar();
printf("请输入点和点之间的连接:(例:1 5 10)\n");
for(i=0;i<G->Arcnum;i++)//循环输入边的信息
{
scanf("%d %d %d",&node1,&node2,&weight);
getchar();
p1=(pArcnode)malloc(sizeof(Arcnode));
p1->adjvex=node2;//构造连接
p1->weight=weight;
p1->next=NULL;
if(G->vertice[node1].firstarc==NULL)//还未有邻接点时
{
G->vertice[node1].firstarc=p1;
}
else//已有邻接点时
{
p1->next=G->vertice[node1].firstarc;
G->vertice[node1].firstarc=p1;
}
}
}
void CalculateIndegree(pGraph G,int indegree[])
{
int i;
pArcnode s;
for(i=0;i<G->Vnum;i++)//入度数组初始化
{
indegree[i]=0;
}
for(i=0;i<G->Vnum;i++)//计算每个点的入度
{
s=G->vertice[i].firstarc;
while(s!=NULL)
{
indegree[s->adjvex]++;
s=s->next;
}
}
}
void TuoPu(pGraph G,int ve[],int Q[])//求拓扑排序,ve【】存储事件开始的最早时间,Q【】队列存储拓扑排序
{
int indegree[G->Vnum];
int head=0,tail=0,temp;
int i;
pArcnode s;
CalculateIndegree(G,indegree);//计算每个点的入度
for(i=0;i<G->Vnum;i++)//初始化事件开始的最早时间
{
ve[i]=0;
}
for(i=0;i<G->Vnum;i++)//寻找一开始入度就为0的点
{
if(indegree[i]==0)//当入度为0时
{
Q[tail]=i;
tail++;
}
}
while(head!=tail)//计算整个图的拓扑排序
{
temp=Q[head];//出队
head++;
s=G->vertice[temp].firstarc;
while(s!=NULL)//消除入度为零的点的后继边
{
indegree[s->adjvex]--;//为该点的后继边指向的点入度减1
if(ve[s->adjvex]<ve[temp]+s->weight)//计算活动最早开始的时间
{
ve[s->adjvex]=ve[temp]+s->weight;
}
if(indegree[s->adjvex]==0)//判断入度减一后是否为入度为0的点
{
Q[tail]=s->adjvex;
tail++;
}
s=s->next;
}
}
if(G->Vnum!=tail)//判断拓扑序列中的点数是否和整个图的点数一样
{
printf("该图不是有向无环图");
}
}
void GetPath(pGraph G,int ve[],int Q[])//求关键路径,ve【】为事件最早开始时间,Q【】为存储拓扑排序的队列
{
int i,j;
int head=0,tail=0,temp;
int vl[G->Vnum],e[G->Arcnum],l[G->Arcnum];//vl【】为事件开始的最晚时间,e【】为活动呢开始的最早时间,l【】为活动开始的最晚时间
int point[G->Arcnum][2];//point【】【】用于存储每个活动的起始事件和终止事件
pArcnode s;
tail=G->Vnum;
for(i=0;i<G->Vnum;i++)//初始化事件最晚开始时间
{
vl[i]=0;
}
vl[Q[tail-1]]=ve[Q[tail-1]];//提出汇点进行计算
tail--;
while(head!=tail)//当头指针和尾指针指向同一个地方时结束,这个循环是为了通过逆拓扑排序计算事件最晚开始的时间
{
temp=Q[tail];//出队操作
tail--;
s=G->vertice[temp].firstarc;
while(s!=NULL)//计算vl
{
if(vl[temp]<ve[s->adjvex]-s->weight)
{
vl[temp]=vl[s->adjvex]-s->weight;
}
s=s->next;
}
}
for(i=0,j=0;i<G->Vnum;i++)//for循环是为了遍历图中每个点
{
s=G->vertice[i].firstarc;
while(s!=NULL)//计算图中每个点(事件)的后继指针(活动)的最早开始时间
{
e[j]=ve[i];
point[j][0]=i;
point[j][1]=s->adjvex;
j++;
s=s->next;
}
}
for(i=0,j=0;i<G->Vnum;i++)//for循环是为了遍历图中每个点
{
s=G->vertice[i].firstarc;
while(s!=NULL)//计算图中每个点(事件)的后继指针(活动)的最晚开始时间
{
l[j]=vl[s->adjvex]-s->weight;
j++;
s=s->next;
}
}
printf("关键路径为:\n");
for(i=0;i<G->Arcnum;i++)//打印关键路径
{
if(e[i]==l[i])
{
printf("%d->%d:%d\n",point[i][0],point[i][1],e[i]);
}
}
}
#include
#include
typedef struct arcnode
{
int weight;//权重
int adjvex;//指向的下一个顶点
struct arcnode *next;//指向这个点的另一条边
}Arcnode,*pArcnode;
typedef struct vnode
{
pArcnode firstarc;//点所指向的第一条边
}Vnode,AdjList[30];
typedef struct graph
{
int Vnum,Arcnum;//点的数目,边的数目
AdjList vertice;
}Graph,*pGraph;
void CreateGraph(pGraph G)//构造AOE网
{
int i;
int node1,node2,weight;//暂时存储数据
pArcnode p1;
printf("请输入有向图的总点数:\n");
scanf("%d",&G->Vnum);
getchar();
for(i=0;i<G->Vnum;i++)//给每个结点的第一个后继边初始化
{
G->vertice[i].firstarc=NULL;
}
printf("请输入无向图的总边数:\n");
scanf("%d",&G->Arcnum);
getchar();
printf("请输入点和点之间的连接:(例:1 5 10)\n");
for(i=0;i<G->Arcnum;i++)//循环输入边的信息
{
scanf("%d %d %d",&node1,&node2,&weight);
getchar();
p1=(pArcnode)malloc(sizeof(Arcnode));
p1->adjvex=node2;//构造连接
p1->weight=weight;
p1->next=NULL;
if(G->vertice[node1].firstarc==NULL)//还未有邻接点时
{
G->vertice[node1].firstarc=p1;
}
else//已有邻接点时
{
p1->next=G->vertice[node1].firstarc;
G->vertice[node1].firstarc=p1;
}
}
}
void CalculateIndegree(pGraph G,int indegree[])
{
int i;
pArcnode s;
for(i=0;i<G->Vnum;i++)//入度数组初始化
{
indegree[i]=0;
}
for(i=0;i<G->Vnum;i++)//计算每个点的入度
{
s=G->vertice[i].firstarc;
while(s!=NULL)
{
indegree[s->adjvex]++;
s=s->next;
}
}
}
void TuoPu(pGraph G,int ve[],int Q[])//求拓扑排序,ve【】存储事件开始的最早时间,Q【】队列存储拓扑排序
{
int indegree[G->Vnum];
int head=0,tail=0,temp;
int i;
pArcnode s;
CalculateIndegree(G,indegree);//计算每个点的入度
for(i=0;i<G->Vnum;i++)//初始化事件开始的最早时间
{
ve[i]=0;
}
for(i=0;i<G->Vnum;i++)//寻找一开始入度就为0的点
{
if(indegree[i]==0)//当入度为0时
{
Q[tail]=i;
tail++;
}
}
while(head!=tail)//计算整个图的拓扑排序
{
temp=Q[head];//出队
head++;
s=G->vertice[temp].firstarc;
while(s!=NULL)//消除入度为零的点的后继边
{
indegree[s->adjvex]--;//为该点的后继边指向的点入度减1
if(ve[s->adjvex]<ve[temp]+s->weight)//计算活动最早开始的时间
{
ve[s->adjvex]=ve[temp]+s->weight;
}
if(indegree[s->adjvex]==0)//判断入度减一后是否为入度为0的点
{
Q[tail]=s->adjvex;
tail++;
}
s=s->next;
}
}
if(G->Vnum!=tail)//判断拓扑序列中的点数是否和整个图的点数一样
{
printf("该图不是有向无环图");
}
}
void GetPath(pGraph G,int ve[],int Q[])//求关键路径,ve【】为事件最早开始时间,Q【】为存储拓扑排序的队列
{
int i,j;
int head=0,tail=0,temp;
int vl[G->Vnum],e[G->Arcnum],l[G->Arcnum];//vl【】为事件开始的最晚时间,e【】为活动呢开始的最早时间,l【】为活动开始的最晚时间
int point[G->Arcnum][2];//point【】【】用于存储每个活动的起始事件和终止事件
pArcnode s;
tail=G->Vnum;
for(i=0;i<G->Vnum;i++)//初始化事件最晚开始时间
{
vl[i]=0;
}
vl[Q[tail-1]]=ve[Q[tail-1]];//提出汇点进行计算
tail--;
while(head!=tail)//当头指针和尾指针指向同一个地方时结束,这个循环是为了通过逆拓扑排序计算事件最晚开始的时间
{
temp=Q[tail];//出队操作
tail--;
s=G->vertice[temp].firstarc;
while(s!=NULL)//计算vl
{
if(vl[temp]<ve[s->adjvex]-s->weight)
{
vl[temp]=vl[s->adjvex]-s->weight;
}
s=s->next;
}
}
for(i=0,j=0;i<G->Vnum;i++)//for循环是为了遍历图中每个点
{
s=G->vertice[i].firstarc;
while(s!=NULL)//计算图中每个点(事件)的后继指针(活动)的最早开始时间
{
e[j]=ve[i];
point[j][0]=i;
point[j][1]=s->adjvex;
j++;
s=s->next;
}
}
for(i=0,j=0;i<G->Vnum;i++)//for循环是为了遍历图中每个点
{
s=G->vertice[i].firstarc;
while(s!=NULL)//计算图中每个点(事件)的后继指针(活动)的最晚开始时间
{
l[j]=vl[s->adjvex]-s->weight;
j++;
s=s->next;
}
}
printf("关键路径为:\n");
for(i=0;i<G->Arcnum;i++)//打印关键路径
{
if(e[i]==l[i])
{
printf("%d->%d:%d\n",point[i][0],point[i][1],e[i]);
}
}
}
int main()
{
pGraph G;
int ve[30];
int Q[50];
G=(pGraph)malloc(sizeof(Graph));
CreateGraph(G);
TuoPu(G,ve,Q);
GetPath(G,ve,Q);
return 0;
}
测试样例
9
11
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 8
4 7 7
5 7 4
6 8 2
7 8 4
结果截图