#include 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 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 dist(n, INF); vector 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 in_neg(n, 0); // 第 n 轮:若还能松弛则相关节点受负环影响(或者能从某个负环传播到) // 我们先把可以被松弛的点入队,然后在图上做 BFS/DFS 向外传播(因为负环的影响会沿有向边传播到可达节点) queue 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> 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 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; }