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

141 lines
4.2 KiB
C++
Raw 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 <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = LLONG_MAX / 4; // 足够大plus 操作不会溢出
struct Edge {
int u, v;
ll w;
Edge(int _u=0, int _v=0, ll _w=0) : u(_u), v(_v), w(_w) {}
};
/*
* Bellman-Ford 竞赛模板
*
* 输入:
* n : 顶点数 (0..n-1)
* m : 边数
* 接下来 m 行,每行 u v w (表示 u -> v 的边权为 w
* s : 源点
*
* 输出(模板示例):
* 对每个顶点 i
* - 若 i 不可达: 输出 "INF"
* - 若 i 可达并且受负环影响(距离可任意减小): 输出 "-INF"
* - 否则 输出最短距离 dist[i]
*
* 另外提供 reconstruct_path(s, t, prev) 重建单源到 t 的一条最短路径(若可重建)
*
* 复杂度O(n * m)
*/
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
if (!(cin >> n >> m)) return 0;
vector<Edge> edges;
edges.reserve(m);
for (int i = 0; i < m; ++i) {
int u, v;
long long w;
cin >> u >> v >> w;
// 若输入为 1-index请在此处做 --u; --v;
edges.emplace_back(u, v, w);
}
int s;
cin >> s; // 源点
// ---------- Bellman-Ford 主体 ----------
vector<ll> dist(n, INF);
vector<int> prev(n, -1); // 用于路径重建
dist[s] = 0;
// 1) 做 n-1 轮松弛,使 dist 收敛(若无负环)
for (int iter = 0; iter < n - 1; ++iter) {
bool updated = false;
for (const auto &e : edges) {
if (dist[e.u] != INF && dist[e.v] > dist[e.u] + e.w) {
dist[e.v] = dist[e.u] + e.w;
prev[e.v] = e.u;
updated = true;
}
}
if (!updated) break; // 提前退出(常见优化)
}
// 2) 检测并标记受负环影响的节点
// nodes_in_neg_cycle[i] == true 表示 i 的距离可以无限减小
vector<char> in_neg(n, 0);
// 第 n 轮:若还能松弛则相关节点受负环影响(或者能从某个负环传播到)
// 我们先把可以被松弛的点入队,然后在图上做 BFS/DFS 向外传播(因为负环的影响会沿有向边传播到可达节点)
queue<int> q;
for (const auto &e : edges) {
if (dist[e.u] != INF && dist[e.v] > dist[e.u] + e.w) {
// e.v 受影响(直接)
if (!in_neg[e.v]) {
in_neg[e.v] = 1;
q.push(e.v);
}
}
}
// 为了传播负环影响,需要图的邻接表(从受影响节点向外传播)
vector<vector<int>> adj_out(n);
for (const auto &e : edges) {
adj_out[e.u].push_back(e.v);
}
// BFS/DFS 从初始受影响节点传播,标记所有可达顶点为受影响
while (!q.empty()) {
int x = q.front(); q.pop();
for (int y : adj_out[x]) {
if (!in_neg[y]) {
in_neg[y] = 1;
q.push(y);
}
}
}
// ---------- 输出结果示例 ----------
// 若想要标准竞赛输出:可根据题目要求调整输出格式
// 下面按通用风格输出每个顶点的状态
for (int i = 0; i < n; ++i) {
if (in_neg[i]) {
cout << "-INF"; // 受负环影响,可以任意小
} else if (dist[i] == INF) {
cout << "INF"; // 不可达
} else {
cout << dist[i]; // 有确定的最短距离
}
if (i + 1 < n) cout << ' ';
}
cout << '\n';
// ---------- 可选:重建单源到某个 t 的路径前提t 不受负环影响且可达) ----------
// 示例:如果输入了一个 t则输出路径
int t;
if (cin >> t) {
if (in_neg[t]) {
cout << "Target node " << t << " is affected by a negative cycle; path undefined.\n";
} else if (dist[t] == INF) {
cout << "No path from " << s << " to " << t << '\n';
} else {
vector<int> path;
for (int cur = t; cur != -1; cur = prev[cur]) {
path.push_back(cur);
}
reverse(path.begin(), path.end());
cout << "Path: ";
for (int x : path) cout << x << ' ';
cout << '\n';
}
}
return 0;
}