【最短路】【Floyd演算法】【模板】 講解 + 例題 HDU 1874 暢通工程續 【求兩點間最短路】
阿新 • • 發佈:2019-02-03
【最短路】【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省略,則新增的元素為預設值。- 注意將
resize
和reserve
函式區分開,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;
}