--- tags: APCS --- # Bellman-Ford 演算法 ``` graphviz digraph G { rankdir=LR splines="line" node[shape=circle] {rank=same;1,2} {rank=same;3,4} 0 -> 1 [label=5] 0 -> 2 [label=-2] 1 -> 3 [label=1] 2 -> 1 [label=2] 2 -> 4 [label=3] 3 -> 2 [label=2] 3 -> 4 [label=7] 3 -> 5 [label=3] 4 -> 5 [label=10] } ``` ``` cpp= #include <iostream> #include <string> #include <sstream> #include <vector> #include <iterator> using namespace std; //--------------------------------------------------------------------------- // 測試資料 // // 第一行,一個整數 n 表示有幾個節點 // 剩下一直到結尾的每一行的 3 個整數都代表一條邊,格式為 v1 v2 w // v1 v2 代表線的兩個端點, // w 代表這條線的權重(或成本) // string input = "\ 6\n\ 0 1 5\n\ 0 2 -2\n\ 1 3 1\n\ 2 1 2\n\ 3 2 2\n\ 2 4 3\n\ 3 4 7\n\ 3 5 3\n\ 4 5 10\n"; //--------------------------------------------------------------------------- // Bellman-Ford 需要窮舉每一條邊來進行鬆弛,所以要包含兩端點 struct Edge { int from, to, weight; }; // 用結構紀錄圖的組態 struct Graph { int n; // 總節點數 vector<Edge> edge; // 所有邊的列表 }; vector<int> sssp_bellman_ford(Graph &g, int src) { vector<int> dist(g.n, INT32_MAX); dist[src] = 0; for (int i = 0; i < g.n; i++) { // 跑 n 個回合 int modified = false; for (auto &e: g.edge) { // 窮舉每條邊進行鬆弛 auto &cur_dist = dist[e.from]; if (cur_dist != INT32_MAX) { // 有值的再處理就可以了,無限大的先跳過 if (cur_dist + e.weight < dist[e.to]) { // 可以鬆弛的話 dist[e.to] = cur_dist + e.weight; // 更新 to 的最短距離 modified = true; // 本回合有更新 } } } if (!modified) // 如果此回合沒有變更,就可以提早離開 break; } return dist; } int main() { stringstream sin(input); Graph G; int a, b, r; sin >> G.n; while (sin >> a >> b >> r) { G.edge.push_back({a, b, r}); } // 印出從每一點當起點時,至各點的最短距離 for (int i = 0; i < G.n; i++) { auto dist = sssp_bellman_ford(G, i); cout << i << ": "; copy(dist.begin(), dist.end(), ostream_iterator<int>(cout, " ")); cout << '\n'; } return 0; } ```