NewCodeTemplate

This commit is contained in:
e2hang
2025-12-16 20:36:27 +08:00
parent 684e35b210
commit 8253f2dcbc
26 changed files with 2547 additions and 0 deletions

127
模板/图/关键路径.cpp Normal file
View File

@@ -0,0 +1,127 @@
#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;
}