说明: AOE 网络是有向无环加权图,其中顶点表示事件,弧表示活动,权表示活动持续的时间,通常可以用来估算工程完成的时间,即图中从开始点到结束点之间最长的路径对应的时间。请完成一个程序,完成下列任务:
1 、计算 AOE 网络对应的拓扑排序。如果排序结果不唯一,请输出按照从小到大的顺序排列的结果。从小到大的顺序就是输入的节点序列顺序(参见下面关于输入格式的说明)。如图1中满足要求的拓扑排序是: a-b-c-d-e-f-g-h-k ,图2中满足要求的拓扑排序是:v1-v3-v5-v2-v6-v4-v7-v8-v9
2 、计算 AOE 网络的关键路径。注意关键路径可能不唯一,要求输出所有的关键路径。同样,按照是按照从小到大的顺序输出。例,如果得到两条关键路径,分别是0-1-3-6-8-9和0-1-3-4-5-8-9,那么先输出后一条路径,因为两条路径中前三个节点相同,而后一条路径第四个节点的编号小。
测试用例的输入输出格式说明:
输入:
节点的个数,边的条数;
各个节点的名称序列
边: < 起点 , 终点 , 权值 > 。说明起点和终点是在各个点在输入序列中的位置,如图1中边 <a,b> 表示为 <0,1,6> 。
输出:
拓扑排序;
关键路径
![](https://i-blog.csdnimg.cn/blog_migrate/25dca3edd86688a04bbb204dd4e170f8.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8a3366c3dc6ce308165336fcbd0ea6d7.jpeg)
测试用例0是与图1相对应的,测试用例1是与图2相对应的。
样例
输入(1)
9,11
a,b,c,d,e,f,g,h,k
<0,1,6>,<0,2,4>,<0,3,5>,<1,4,1>,<2,4,1>,<4,6,8>,<4,7,7>,<3,5,2>,<5,7,4>,<6,8,2>,<7,8,4>
输出(1)
a-b-c-d-e-f-g-h-k
a-b-e-h-k
输入(2)
9,11
v1,v2,v3,v4,v5,v6,v7,v8,v9
<0,4,6>,<0,2,4>,<0,5,5>,<4,1,1>,<2,1,1>,<1,6,8>,<1,7,7>,<5,3,2>,<3,7,4>,<6,8,2>,<7,8,4>
输出(2)
v1-v3-v5-v2-v6-v4-v7-v8-v9
v1-v5-v2-v8-v9
输入(3)
4,4
A,B,C,D
<0,1,2>,<1,3,3>,<3,2,5>,<2,1,1>
输出(3)
NO TOPOLOGICAL PATH
代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int vnum, arcnum;
int topo[55], path[100];
struct link
{
int dir;//目标位置
int weight;//权值
};
struct vex
{
char name[5];
int inNum = 0; //入度
int outNum = 0; //出度
int ve, vl; //事件的最早和最晚发生时间
link linkTo[300];
int linkNum = 0;
};
vex node[50];
int comp(const void*a,const void*b)
{
return *(int*)a-*(int*)b; //从小到大
}
int comp2(const void*a,const void*b)
{
return *(int*)b-*(int*)a; //从大到小
}
/*把顶点和边信息读入到表示图的邻接表中*/
void CreateGraph()
{
char str[500] = { '\0' };
scanf("%s",str);
int len = strlen(str), q = 0, k = 0;
for (int i = 0; i < len; i++)
{
if (str[i] != ',')
node[k].name[q++] = str[i];
else
{
node[k].name[q] = '\0';
k++;
q = 0;
}
}
getchar();
int a,b,c;
for(int i=0;i<arcnum;++i) //建立邻接链表
{
scanf("<%d,%d,%d>",&a,&b,&c);
node[b].inNum++;
node[a].outNum++;
node[a].linkTo[node[a].linkNum].dir=b;
node[a].linkTo[node[a].linkNum].weight=c;
node[a].linkNum++;
getchar();
}
for (int i = 0; i < vnum; i++) //对邻节点排序
qsort(node[i].linkTo, node[i].linkNum, sizeof(node[i].linkTo[0]), comp); //linkNum
}
/*广度优先搜索获取拓扑序列 */
int TopoLogicalSort_DFS()
{
int *Stack, u, v, top = 0, count = 0;
Stack = (int*)malloc(sizeof(int) * vnum);
for (int i = 0; i < vnum; i++)//将度为0的顶点入栈
{
node[i].ve = 0;
if (node[i].inNum == 0) Stack[top++] = i;
}
while (top > 0)
{
u = Stack[--top]; //取栈顶
topo[count++] = u;
for (int i = 0; i <= node[u].linkNum; i++)//将u的邻接点入度减1,并将入度为0的顶点入栈
{
int v = node[u].linkTo[i].dir;
if (node[v].ve < node[u].ve + node[u].linkTo[i].weight) node[v].ve = node[u].ve + node[u].linkTo[i].weight;
if (--node[v].inNum == 0) Stack[top++] = v;
}
qsort(Stack, top, sizeof(Stack[0]), comp2);//从大到小入栈
}
free(Stack);
return (count == vnum) ? 1 : 0;
}
/*路径输出*/
void PrintPath(int top, int end)
{
int u = path[top - 1];
if (u == end)
{
printf("%s", node[path[0]].name); //输出关键路径
for (int i = 1; i < top; i++)
printf("-%s", node[path[i]].name);
printf("\n");
return;
}
for (int i = 0; i <= node[u].linkNum; i++)
{
int v = node[u].linkTo[i].dir;
if (node[u].ve + node[u].linkTo[i].weight < node[v].ve) continue;
if (node[v].ve == node[v].vl)//关键事件
{
path[top++] = node[u].linkTo[i].dir;//入栈
PrintPath(top, end); //递归
top--;//退栈
}
}
}
/*求关键路径*/
void CriticalPath()
{
if (!TopoLogicalSort_DFS())
{
printf("NO TOPOLOGICAL PATH\n");
return;
}
for (int i = 0; i < vnum; i++)
{
node[i].vl = node[vnum - 1].ve; //初始化各事件最晚发生事件为最后一个事件发生的时间
if (i) printf("-");
printf("%s", node[topo[i]].name); //打印拓扑序列
}
printf("\n");
for (int i = vnum - 2; i >= 0; i--)
{
int u = topo[i];
for (int j = 0; j <= node[u].linkNum; j++)
{
int v = node[u].linkTo[j].dir;
if (node[u].vl > node[v].vl - node[u].linkTo[j].weight) node[u].vl = node[v].vl - node[u].linkTo[j].weight;
}
}
path[0] = topo[0];
PrintPath(1, topo[vnum - 1]);
}
int main()
{
scanf("%d,%d", &vnum, &arcnum);
CreateGraph();//把顶点和边信息读入到表示图的邻接表中
CriticalPath();//求关键路径
return 0;
}