1. 程式人生 > >Bellman-Ford演算法和佇列優化(SPFA)——求單源最短路徑

Bellman-Ford演算法和佇列優化(SPFA)——求單源最短路徑

來源自我的部落格

#include <stdio.h>
#include <limits.h>
int main(){
    int n, m;
    scanf("%d%d", &n, &m);

    int u[10], v[10], w[10];    // 分別表示邊的兩頂點編號和權值
    for (int i = 1; i <= m; i++){
        scanf("%d%d%d", &u[i], &v[i], &w[i]);
    }

    int dis[10];    // 源點到任意點的距離
for (int i = 1; i <= n; i++){ dis[i] = INT_MAX; } dis[1] = 0; int bak[i]; // 核心語句,迴圈n-1次 for (int k = 1; k <= n - 1; k++){ // 備份距離陣列以檢測是否已完成 for (int i = 1; i <= n; i++) bak[i] = dis[i]; // 每次迴圈遍歷所有邊 for (int i = 1; i <= m; i++){ // 判斷源點到點v[i]距離能不能通過走源點->點u[i]->點v[i]的路線更短
if (dis[v[i]] > dis[u[i]] + w[i]){ dis[v[i]] = dis[u[i]] + w[i]; } } // 迴圈完檢測當前dis是否有更新 bool check = 0; for (int i = 1; i <= n; i++) { if (bak[i] != dis[i]) { check = 1; break; } } if
(check = 0) break; // 如果 dis陣列沒更新,提前退出迴圈 } // 檢測負權迴路 bool flag = 0; for (int i = 1; i <= m; i++){ if (dis[v[i]] > dis[u[i]] + w[i]) flag = 1; } if (flag == 1) printf("有負權迴路\n"); // 輸出最終結果 for (int i = 1; i <= n; i++){ printf("%d ", dis[i]); } return 0; }
// 佇列優化的Bellman-Ford演算法(SPFA演算法)
#include <iostream>
#include <climits>
#include <queue>
#include <vector>
using namespace std;

int main(){
    int n, m;
    cin >> n >> m;

    vector <int> dis(n, INT_MAX);   // 源點到每個點的距離
    dis[0] = 0;

    vector <int> first(n, -1);  // 每個結點相鄰的邊中第一條邊的編號,-1表示沒有相鄰的邊
    vector <int> next(m, -1);   // 每條邊的下一條邊的編號

    vector <bool> book(n, false);   // true表示在佇列中

    vector <int> u(m), v(m), w(m);  // 每條邊的兩頂點和權值

    // 建立鄰接表
    for (int i = 0; i < m; i++){
        cin >> u[i] >> v[i] >> w[i];
        // 將新邊頭插到鄰接表中
        next[i] = first[u[i]];  // 此邊的下一邊為u[i]起頭的第一條邊
        first[u[i]] = i;    // 將此邊作為u[i]起頭的第一條邊
    }

    queue <int> Q;
    // 將源點入佇列
    Q.push(0);
    book[0] = true;

    // 佇列不空時迴圈
    while (!Q.empty()){
        // 取隊首
        int k = first[Q.front()];   // k表示隊首點的第一條鄰接邊的編號
        // 掃描隊首頂點所有的鄰邊
        while (k != -1){
            // 判斷源點到點v[k]的距離能不能通過源點->點u[k]->點v[k]來更新
            if (dis[v[k]] > dis[u[k]] + w[k]){
                dis[v[k]] = dis[u[k]] + w[k];

                // 判斷點v[k]在不在佇列中
                if (book[v[k]] == false){
                    // 不在佇列中則入隊
                    Q.push(v[k]);
                    book[v[k]] = true;
                }
            }
            // k移向下一條鄰接邊
            k = next[k];
        }
        // 隊首結點用完了,可以出隊了
        book[Q.front()] = false;
        Q.pop();
    }

    // 輸出源點到其餘各個頂點的最短路徑
    for (int i = 0; i < n; i++){
        cout << dis[i] << " ";
    }
    cout << endl;

    return 0;
}