1. 程式人生 > >【最短路】【Floyd演算法】【模板】 講解 + 例題 HDU 1874 暢通工程續 【求兩點間最短路】

【最短路】【Floyd演算法】【模板】 講解 + 例題 HDU 1874 暢通工程續 【求兩點間最短路】

【最短路】【Floyd演算法】【模板】講解 + 例題 HDU 1874 暢通工程續

Floyd演算法講解

  • 適用情況:多源多匯最短路(即求任意兩點間的最短路)
  • 複雜度: O(v^3)
  • 思想: DP 通過列舉中間點來優化它的時間複雜度
    • d[i][j][k]表示從i到j在節點只允許經過[0,k]時的最短距離
    • a. 如果最短路經過k點,則d[i][j][ k ] = d[i][k][k-1] + d[k][j][k-1]
    • b. 如果最短路不經過k點,則d[i][j][k] = d[i][j][k-1]
    • 於是有狀態轉移方程: d[i][j][k] = min{ d[i][j][k-1], d[i][k][k-1] + d[k][j][k-1] }
    • 一般省去後面一維,變為二維:d[i][j] = min{d[i][j], d[i][k] + d[k][j]}

模板:

  • 核心程式碼:
for(int k = 0; k < n; k++)
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
        {
            if(dis[i][k] < INF && dis[k][j] < INF)
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
        }
  • 初始化:
vector<vector<int> > dis(n);//vector二維可變長陣列

for(int i = 0; i < n; i++)
{
    dis[i].resize(n, INF);//初始化設定dis[i]的長度,並用INF作為初始值
    dis[i][i] = 0;
}

for(int i = 0; i < m; i++)//輸入邊
{
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    dis[u][v] = dis[v][u] = w;//雙向邊
}
  • TIPS:
    • 這裡用 vector<vector<int> >作為二維陣列來儲存邊,其中定義是要用dis(n)(n)用於初始化長度,不可以寫作[n]
    • resize(n, val)函式用於重新確定大小,可以在容器的尾部新增或者刪除一些元素,來調整容器的大小使其達到指定的大小,如果需要新增元素,那麼新增的元素值為val,如果val省略,則新增的元素為預設值。
    • 注意將resizereserve函式區分開,reserve函式是用於重新分配空間,表示容量(capacity)。比如現在要建一輛公共汽車,用reserve分配了20個座位的空間,此時只能說明這輛車有20個座位這麼大,但裡面並沒有座位,還需要用resize給汽車安裝20個座位,有了座位後,才可以設定每個座位的值。

例題 HDU 1874 暢通工程續

Problem Description

某省自從實行了很多年的暢通工程計劃後,終於修建了很多路。不過路多了也不好,每次要從一個城鎮到另一個城鎮時,

都有許多種道路方案可以選擇,而某些方案要比另一些方案行走的距離要短很多。這讓行人很困擾。

現在,已知起點和終點,請你計算出要從起點到終點,最短需要行走多少距離。

Input

本題目包含多組資料,請處理到檔案結束。
每組資料第一行包含兩個正整數N和M(0 < N < 200,0 < M < 1000),

分別代表現有城鎮的數目和已修建的道路的數目。城鎮分別以0~N-1編號。
接下來是M行道路資訊。每一行有三個整數A,B,X(0 <= A,B < N, A != B, 0 < X < 10000), 表示城鎮A和城鎮B

之間有一條長度為X的雙向道路。
再接下一行有兩個整數S,T(0 <= S, T < N),分別代表起點和終點。

Output

對於每組資料,請在一行裡輸出最短需要行走的距離。如果不存在從S到T的路線,就輸出-1.

Sample Input

3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2

Sample Output

2
-1

題意:
給出起點和終點,求最短路

思路:
求任意兩點的最短距離,可以用floyd處理,但是這裡要注意的是,兩個城市間可能有多條路,所以需要儲存最短的路徑!

AC程式碼:

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <queue>
#include <vector>
#define INF 0x3f3f3f3f

using namespace std;

int main()
{
    int n, m, s, t;
    while(~scanf("%d%d", &n, &m))
    {
        vector<vector<int> > dis(n);
        for(int i = 0; i < n; i++)
        {
            dis[i].resize(n, INF);
            dis[i][i] = 0;
        }
        for(int i = 0; i < m; i++)
        {
            int a, b, x;
            scanf("%d%d%d", &a, &b, &x);
            if(dis[a][b] > x)
                dis[a][b] = dis[b][a] = x;
        }
        scanf("%d%d", &s, &t);
        for(int k = 0; k < n; k++)
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                {
                    if(dis[i][k] < INF && dis[k][j] < INF)
                        dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
                }
        if(dis[s][t] != INF)
            printf("%d\n", dis[s][t]);
        else
            printf("-1\n");
    }
    return 0;
}