Files
Data-Structure/模板//关键路径.cpp
2025-12-16 20:36:27 +08:00

128 lines
3.4 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <limits>
using namespace std;
/*
* 关键路径算法基于 AOE 网络Activity on Edge
* 图必须是有向无环图DAG
* 每条边 (u -> v) 表示一个活动,权值 w 表示活动耗时
*
* 核心步骤:
* 1. 用拓扑排序顺序计算每个事件的最早发生时间 ve[]
* 2. 逆拓扑顺序计算每个事件的最晚发生时间 vl[]
* 3. 找出所有满足 ve[u] + w == vl[v] 的活动(关键活动)
* 4. 关键活动连线形成关键路径
*/
struct Edge {
int to; // 终点事件编号
int w; // 活动耗时
};
int main() {
int n, e;
cin >> n >> e;
vector<vector<Edge>> adj(n); // 邻接表:活动在边上
vector<int> indeg(n, 0); // 各事件的入度
int u, v, w;
for (int i = 0; i < e; i++) {
cin >> u >> v >> w;
adj[u].push_back({v, w});
indeg[v]++; // 事件 v 的前置事件数加 1
}
//
// 第一步:拓扑排序,计算 ve[]
//
vector<int> topo; // 拓扑序
queue<int> q; // 用普通队列即可(要求的是顺序,不是字典序)
vector<int> ve(n, 0); // 事件最早发生时间(从起点开始的最长路径)
// 入度为 0 的事件作为起始点
for (int i = 0; i < n; i++) {
if (indeg[i] == 0) q.push(i);
}
while (!q.empty()) {
int x = q.front(); q.pop();
topo.push_back(x);
// 用此事件更新其后继事件的最早发生时间
for (auto &edge : adj[x]) {
int y = edge.to;
int cost = edge.w;
// ve[y] = max(ve[y], ve[x] + cost)
ve[y] = max(ve[y], ve[x] + cost);
// 拓扑排序削减入度
if (--indeg[y] == 0) {
q.push(y);
}
}
}
// 如果拓扑序中事件数 != n则图中存在环
if ((int)topo.size() != n) {
cout << "The graph has a cycle. Critical path undefined." << endl;
return 0;
}
//
// 第二步:逆拓扑序,计算 vl[]
//
vector<int> vl(n, numeric_limits<int>::max());
// 终点事件的最晚时间 = 其最早时间
// 注意:可能有多个终点,因此我们取所有 ve[] 中的最大值
int maxEndTime = 0;
for (int i = 0; i < n; i++) {
maxEndTime = max(maxEndTime, ve[i]);
}
// 所有事件的最晚事件先设为 maxEndTime
for (int i = 0; i < n; i++) {
vl[i] = maxEndTime;
}
// 按拓扑序的反顺序遍历
for (int i = n - 1; i >= 0; i--) {
int x = topo[i];
// 遍历 x 的所有后继活动
for (auto &edge : adj[x]) {
int y = edge.to;
int cost = edge.w;
// vl[x] = min(vl[x], vl[y] - cost)
vl[x] = min(vl[x], vl[y] - cost);
}
}
//
// 第三步:找关键活动(关键边)
//
cout << "Critical Activities:" << endl;
for (int x = 0; x < n; x++) {
for (auto &edge : adj[x]) {
int y = edge.to;
int cost = edge.w;
// 判断活动 (x -> y) 是否关键
if (ve[x] + cost == vl[y]) {
cout << x << " -> " << y << " (cost = " << cost << ")" << endl;
}
}
}
cout << "Total project time = " << maxEndTime << endl;
return 0;
}