实验内容
查找工程图的关键活动
基本内容:
对于给定的如下有向工程施工图,找出该工程图的关键活动。
实验思路:
采取邻接矩阵的方式存储图。
第一步:利用拓扑排序过程计算每个节点的最早开始时间Ve
第二步:利用第一步中的到的拓扑序列的逆序,计算每个节点的最迟开始时间Vl
第三步:利用Ve和Vl计算每个活动的最早开始时间和最迟开始时间e,l
第四步:从起点开始,遍历邻接表中的每条边,若该边的e=l,则此边代表的活动是关键活动,输出
代码
#include <stdio.h>
#include <stdlib.h>
#define max 10000
int main()
{
int u,v,w;
int count=1;
/*创建一个邻接矩阵*/
int nodenum/*节点数*/,arcnum/*边数*/,i,j,k,z;
printf("请输入节点数目和边数:");
scanf("%d",&nodenum);
scanf("%d",&arcnum);
int adj[nodenum+1][nodenum+1];//adjmatrix
/*初始化矩阵*/
for (i=0; i<nodenum+1; i++)
{
for (j=1; j<nodenum+1; j++)
{
adj[i][j]=max;
}
}
/*adj的出度入度记录初始化*/
for (k=0; k<nodenum+1; k++)
{
adj[0][k]=0;//出度
adj[k][0]=0;//入度
}
int ve[nodenum+1],vl[nodenum+1],ae[arcnum+1],al[arcnum+1];/*有点浪费第一个【0】的位置,但是后面不费脑子*/
int s[nodenum]/*栈*/,arc[arcnum+1][2]/*记录边邻接的有哪些节点*/;
/*输入边与权值来构成邻接矩阵*/
printf("请输入边和权值:\n");
j=0;
while (j<arcnum)
{
scanf("%d%d%d",&u,&v,&w);
adj[u][v]=w;
adj[v][0]++;
adj[0][u]++;
arc[j+1][0]=u;
arc[j+1][1]=v;
j++;
}
/*求ve*/
/*初始化ve*/
for (i=0; i<nodenum; i++)
{
ve[i]=0;
}
/*搜索一遍入度为0的节点,让其对应的ve最早发生时间为0,且节点入栈*/
j=-1;
for (i=1; i<nodenum+1; i++)
{
if(adj[i][0]==0)
{
j++;
s[j]=i;
}
}
/*用栈更新每个事件的最早发生时间*/
while (j>=0)
{
k=s[j];
j--;/*退栈*/
for (z=1; z<nodenum+1; z++)/*将这个退栈的这个元素所对应的所有结点都遍历*/
{
if (z==k)continue;
if (adj[k][z]>=max)continue;/*若这个退栈的结点与当前遍历的节点没有路径就进行下一个遍历*/
else
{
adj[z][0]--;/*有路径就将这个对应的结点入度减一*/
if (adj[z][0]==0) /*若节点入度已经降为0就入栈*/
{
j++;
s[j]=z;
count++;
}
}
if (adj[k][z]+ve[k]<ve[z])continue;/*如果当前的事件已经是最早发生时间了,就跳过*/
else
{
ve[z]=adj[k][z]+ve[k];/*此时得出的是最晚的发生时间则替代当前的节点*/
}
}
}
if(count!=nodenum)printf("这个图有环!不能得出关键活动与关键路径!");
/*求vl*/
/*初始化vl*/
for (i=0; i<nodenum; i++)
{
vl[i]=max;
}
/*搜索一遍出度为0的节点,节点入栈*/
j=-1;
for (i=1; i<nodenum+1; i++)
{
if(adj[0][i]==0)
{
vl[i]=ve[i];
j++;
s[j]=i;
}
}
while (j>=0)
{
k=s[j];
j--;/*退栈*/
for (z=1; z<nodenum+1; z++)/*将这个退栈的这个元素所对应的所有结点都遍历*/
{
if (z==k)continue;
if (adj[z][k]>=max)continue;/*若这个退栈的结点与当前遍历的节点没有路径就进行下一个遍历*/
else
{
adj[0][z]--;/*有路径就将这个对应的结点出度减一*/
if (adj[0][z]==0) /*若节点出度已经降为0就入栈*/
{
j++;
s[j]=z;
}
}
if (vl[k]-adj[z][k]<vl[z])vl[z]=vl[k]-adj[z][k];/*此时得出的是最晚的发生时间则替代当前的节点*/
}
}
/*用ve与vl对应着每条边的两个结点与arc来生成ae与al*/
for (i=1; i<arcnum+1; i++)
{
ae[i]=ve[arc[i][0]];
al[i]=vl[arc[i][1]]-adj[arc[i][0]][arc[i][1]];
}
int l,o;
//print adj;
printf("邻接矩阵:\n");
for (l=0; l<nodenum+1; l++)
{
for (o=0; o<nodenum+1; o++)
{
printf("%7d ",adj[l][o]);
}
printf("\n");
}
printf("\n");
//print ve,vl,ae,al;
printf("各结点的最早发生时间(ve):");
for (l=1; l<nodenum+1; l++)
{
printf("%d ",ve[l]);
}
printf("\n");
printf("各结点的最晚发生时间(vl):");
for (l=1; l<nodenum+1; l++)
{
printf("%d ",vl[l]);
}
printf("\n");
printf("各活动的最早开始时间(ae):");
for (l=1; l<arcnum+1; l++)
{
printf("%d ",ae[l]);
}
printf("\n");
printf("各活动的最晚开始时间(al):");
for (l=1; l<arcnum+1; l++)
{
printf("%d ",al[l]);
}
printf("\n\n");
//print important arc
printf("关键活动:");
for (l=1; l<arcnum+1; l++)
{
if (ae[l]==al[l]) printf("a%d ",l);
}
return 0;
007D
运行结果:
输入数据:
请输入节点数目和边数:9 11
请输入边和权值:
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 4
输出结果: