注:本文采用拓扑排序和关键路径算法求关键路径权值和
Description |
题目内容:对一个工程网,计算完成工程的最短工期。根据输入建立有向带权图,并验证有向无环图,利用拓扑排序,求出关键路径,计算工期。 说明:输入第一行为结点数;第二行为各结点名称;第三行至最后为带权的有向边。 输出为:关键路径的关键活动权值和,即该工程的最短工期。 |
Sample Input |
9 A B C D E F G H M A B 3 A C 10 B D 9 B E 13 C E 12 C F 7 D G 8 D H 4 E H 6 F H 11 G M 2 H M 5 |
Sample Output |
33 |
Hint |
输出有换行符 |
#include <bits/stdc++.h>
#define Maxnum 1005
#define Maxint 32767
using namespace std;
stack<int> S; // 拓扑排序的顶点栈
stack<int> T; // 入度为0的顶点栈
// 邻接表的存储结构
typedef struct Arcnode
{
int adjvex; // 邻接点下标
struct Arcnode *nextarc;
int info; // 权值
};
typedef struct Vnode
{ // 邻接链表
int indu = 0; // 入度
char data;
Arcnode *firstarc;
} Vnode, Adjlist[Maxnum];
typedef struct
{
Adjlist verices;
int vex, arc;
} ALG;
int locatevex(ALG G, char v)
{ // 查找函数
int i;
for (int i = 0; i < G.vex; i++)
{
if (v == G.verices[i].data)
{
return i;
}
}
}
void creatALG(ALG &G)
{ // 有向网的创建
cin >> G.vex;
char v1, v2;
for (int i = 0; i < G.vex; i++)
{
cin >> G.verices[i].data;
G.verices[i].firstarc = NULL;
}
int in;
while (cin >> v1 >> v2 >> in)
{ // 输入结点和权值
int i = locatevex(G, v1); // 查找对应下标
int j = locatevex(G, v2);
Arcnode *p = new Arcnode;
p->adjvex = j;
G.verices[j].indu++; // 记录每个结点的入度
p->info = in;
p->nextarc = G.verices[i].firstarc;
G.verices[i].firstarc = p;
}
}
int ve[Maxnum], vl[Maxnum]; // ve最早发生时间 vl最晚发生时间
void Topu(ALG G)
{ // 拓扑排序记录顶点栈和最早发生数组ve
int j, p, k, cnt = 0, indegree[Maxnum]; // indegree为入度数组对应结点下标
for (int i = 0; i < G.vex; i++)
{ // 初始化
ve[i] = 0;
indegree[i] = G.verices[i].indu;
// cout << indegree[i] << " ";
if (G.verices[i].indu == 0)
T.push(i); // 入栈
}
while (!T.empty())
{
Arcnode *p = new Arcnode;
j = T.top();
T.pop();
S.push(j); // j号顶点入S拓扑排序栈
cnt++;
for (p = G.verices[j].firstarc; p; p = p->nextarc)
{ // 遍历改点邻接结点
k = p->adjvex; // 对应j号结点的邻接点的每个入度减1
if (--indegree[k] == 0) // 如果入度为0,进栈
T.push(k);
if (ve[j] + p->info > ve[k]) // 更新该结点的最早发生时间
ve[k] = ve[j] + p->info;
}
}
}
void Critical(ALG G, int &num)
{ // 关键路径
int j, k, dut;
Arcnode *p = new Arcnode;
for (int i = 0; i < G.vex; i++)
{ // 初始化每个结点的最迟都为结束结点的最早发生时间
vl[i] = ve[G.vex - 1];
}
while (!S.empty())
{ // 按拓扑排序顶点栈求各顶点的vl
for (j = S.top(), S.pop(), p = G.verices[j].firstarc; p; p = p->nextarc)
{ // 取栈顶并遍历每个邻接点
k = p->adjvex;
dut = p->info;
if (vl[k] - dut < vl[j]) // 更新最晚发生时间vl
vl[j] = vl[k] - dut;
}
}
int cnt1, cnt2 = 0; // 记录前一段弧的的结点下标
for (j = 0; j < G.vex; j++)
{ // 求关键路径
for (p = G.verices[j].firstarc; p; p = p->nextarc)
{
k = p->adjvex; // k为邻接点
dut = p->info; // 权值
int ee, el; // ee为每个结点最早发生时间 el为每个结点最晚发生时间
char tag;
ee = ve[j];
el = vl[k] - dut;
// tag = (ee == el) ? '*' : '#';
if (ee == el && j != cnt1 && j == cnt2) // 防止有多条关键路径
{ // 最早和最晚相同为关键事件
num += dut; // 权值加和
cnt1 = j;
cnt2 = k;
}
// cout << j << " " << k << " " << dut << " " << ee << " " << el << " " << tag << "\n";
}
}
}
int main()
{
ALG G;
int num = 0; // 关键路径权值和
creatALG(G);
Topu(G);
Critical(G, num);
cout << num << "\n";
return 0;
}