藍橋杯-算法訓練--ALGO-5 最短路


問題描述

給定一個n個頂點,m條邊的有向圖(其中某些邊權可能為負,但保證沒有負環)。請你計算從1號點到其他點的最短路(頂點從1到n編號)。

輸入格式

第一行兩個整數n, m。

接下來的m行,每行有三個整數u, v, l,表示u到v有一條長度為l的邊。

輸出格式
共n-1行,第i行表示1號點到i+1號點的最短路。
樣例輸入
3 3
1 2 -1
2 3 -1
3 1 2
樣例輸出
-1
-2
數據規模與約定

對於10%的數據,n = 2,m = 2。

對於30%的數據,n <= 5,m <= 10。

對於100%的數據,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保證從任意頂點都能到達其他所有頂點。

 
 
一開始的時候規模少看了一個零( =  = !!)  
用了寫起來比較簡單的floyd算法自己變形了一下,以下錯誤代碼:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 20001;
int floyd[MAXN][MAXN];
int main(){
    int m, n;
    memset(floyd, 2, sizeof(floyd));
    cin >> m >> n;
    for (int i = 1; i <= m; i++){
        int from, to, value;
        cin >> from >> to >> value;
        floyd[from][to] = value;
    }
    for (int j = 1; j <= n; j++)
        for (int k = 1; k <= n; k++){
            if (floyd[1][k] + floyd[k][j] < floyd[1][j])
                floyd[1][j] = floyd[1][k] + floyd[k][j];
        }
    for (int m = 2; m <= n; m++)
        cout << floyd[1][m] << endl;
    return 0;
    }

 

上網查了一下發現SPFA算法,利用隊列優化了一下。

SPFA(Shortest Path Faster Algorithm)(隊列優化)算法是求單源最短路徑的一種算法,它還有一個重要的功能是判負環(在差分約束系統中會得以體現),在Bellman-ford算法的基礎上加上一個隊列優化,減少了冗余的松弛操作,是一種高效的最短路算法。

 

算法大致思路:

  s表示源點

  利用dist[x]表示從源點s到x的最短距離

  用Q隊列來保存需要處理的結點

  用inQueue[x]保存點x是否在隊列中

  初始化:dist[]數組全部賦值為無窮大,比如INT_MAX(一定要足夠大, 我一開始就是給小了所以有些數據錯了)

  dist[s] = 0

開始算法:隊列+松弛操作

  讀取Q隊首元素並出隊(記得把inQueue[Q.top()]置為false)

  對與隊首結點相連的所有點v進行松弛操作(如果源點通過隊首結點再到結點v的距離比源點直接到v的距離要短,就更新dist[v],並且如果inQueue[v] == false 即V當前不在隊列中,則v入隊,當隊列Q為空時,判斷結束)

 

代碼如下:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int MAXN = 20001;
    const int MAXL = 200001;
    const int INF = INT_MAX;   
    int dist[MAXN];          //dist[x]表示從源點到x所需的最短距離,初始為INF
    int head[MAXN];
    int M;      //邊的索引
    bool inQueue[MAXN];
    queue<int> Q;           //隊列Q用來存放可松弛周圍結點的結點
    struct Edge{
        int value;
        int to;
        int next;
    }edge[MAXL];                   //采用鏈式前向星存儲邊集

    //構建邊集合
    void add(int from, int to, int value){
        edge[M].to = to;
        edge[M].next = head[from];
        edge[M].value = value;
        head[from] = M++;
    }

    //SPFA算法
    void SPFA(int start){
        dist[start] = 0;             //源點到自己的距離為0
        Q.push(start);
        inQueue[start] = true;
        while (!Q.empty()){
            int temp = Q.front();        //取隊頭元素
            Q.pop();
            for (int j = head[temp]; j != -1; j = edge[j].next){
                int toNode = edge[j].to;
                if (dist[toNode] > dist[temp] + edge[j].value){        //本題保證無負環,否則需要利用一個數組判斷j是否入隊超過n次    
                    dist[toNode] = dist[temp] + edge[j].value;
                    if (!inQueue[toNode]){
                        Q.push(toNode);
                        inQueue[toNode] = true;
                    }
                }
            }
            inQueue[temp] = false;
        }
    }
    int main(){
        memset(head, -1, sizeof(head));
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++){         //初始化
            dist[i] = INF;
            inQueue[i] = false;
        }
        for (int p = 1; p <= m; p++){
            int from, to, value;
            scanf("%d%d%d", &from, &to, &value);            //用cin速度好像要慢一倍= =
            add(from, to, value);
        }
        SPFA(1);
        for (int x = 2; x <= n; x++){
            printf("%d\n", dist[x]);
        }
        return 0;
    }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM