说明: 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> 。
输出:
拓扑排序;
关键路径
测试用例0是与图1相对应的,测试用例1是与图2相对应的。
测试输入![]() | 期待的输出![]() | 时间限制![]() | 内存限制![]() | 额外进程![]() | |
---|---|---|---|---|---|
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
测试用例 2 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
测试用例 3 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
#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;
}