思路:所谓关键活动即该结点的最早启动时间与最晚启动时间相等。而最早启动时间与图八的一样,关键是获得结点的最晚启动0时间,与最早启动时间相对应,最早启动时间是获得入度为的点---即出发点,最晚启动时间出度为0,逆序遍历,最晚启动时间是后一个结点减活动所需时间中的最小值,遍历时若结点的出度为0则压入队列内,最后比较最早启动时间和最晚启动时间,两者相等,则该节点参与了关键活动,找到该结点指向的另一个结点。
#include<iostream>
using namespace std;
#include<queue>
#define MaxNum 101
#define INF 9999999
using namespace std;
int Node[MaxNum][MaxNum], N, M, indegree[MaxNum] = { 0 }, outdegree[MaxNum] = { 0 }, earlyTime[MaxNum] = { 0 }, lateTime[MaxNum]= {INF};
int getMaxTime(int earlyTime[]) {//找出所有点的最大时间的最大值
int MaxTime = 0;
for (int i = 1; i <=N; i++) {
if (earlyTime[i] > MaxTime) {
MaxTime = earlyTime[i];
}
}
return MaxTime;
}
int TopSort() {//得到各个活动的最早启动时间
int counter = 0, MaxTime = 0;//counter为计数器
queue<int> q;
for (int i = 1; i <= N; i++) {//将所有入度为0的点加入队列内,即开始的点
if (indegree[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
int k = q.front();
q.pop();
counter++;//计算所有遍历点的个数
for (int i = 1; i <= N; i++) {
if (Node[k][i] != INF) {
if (earlyTime[k] + Node[k][i] > earlyTime[i]) {//如果对于当前的最大时间可以更新的话,进行更新
earlyTime[i] = earlyTime[k] + Node[k][i];
}
if (--indegree[i] == 0) {//如果更新后删除k到i的这条边,意义上是对i的入度减一
q.push(i);//如果入度为0,则压入队列
}
}
}
}
MaxTime = getMaxTime(earlyTime);
if (counter != N) {
return -1;
}
else {
return MaxTime;
}
}
void getLateTime() {//得到各个活动的最晚启动时间,最晚减去最早就是活动的机动时间,
queue<int>p;
for (int i = 1; i <= N; i++) {//从最后一个结点开始往后遍历
if (outdegree[i] == 0) {
p.push(i);
}
}
while (!p.empty()) {
int k = p.front();
p.pop();
for (int i = 1; i <= N; i++) {
if (Node[i][k] != INF) {
if (lateTime[k] - Node[i][k] < lateTime[i]) {
lateTime[i] = lateTime[k] - Node[i][k];//最小值即为该结点的最晚启动时间
}
if (--outdegree[i] == 0) {//如果结点的出度为0,说明之后已经没有结点,压入队列
p.push(i);
}
}
}
}
}
int main()
{
cin >> N >> M;
for (int i = 1; i <= N; i++) {//对活动图进行初始化
lateTime[i] = INF;
for (int j = 1; j <= N; j++) {
Node[i][j] = INF;
}
}
for (int k = 0; k < M; k++) {
int i, j, time;//输入数据
cin >> i >> j >> time;
Node[i][j] = time;
indegree[j]++;
outdegree[i]++;
}
int flag= TopSort();
if (flag == -1) {
cout << "0";
}
else {
cout << flag << endl;
lateTime[N] = flag;
getLateTime();
for (int i = 1; i <= N; i++) {
if (earlyTime[i] != lateTime[i]) {//遍历结点,若最晚时间等于最早时间说明该结点的获得活动为关键活动
continue;
}
else {
for (int j = 1; j <= N; j++) {//寻找与i组成关键活动的下一个结点
if (earlyTime[j] == lateTime[j] && Node[i][j] != INF&&earlyTime[j] - Node[i][j] == lateTime[i]) {
cout << i << "->" << j << endl;
}
}
}
}
}
return 0;
}