[圖論]最短路徑問題 :Floyed-Warshall

最短路徑問題


Description

平面上有n個點(N<=100),每個點的座標均在-10000~10000之間。其中的一些點之間有連線。若有連線,則表示可從一個點到達另一個點,即兩點間有通路,通路的距離爲兩點直線的距離。現在的任務是找出從一點到另一點之間的最短路徑。


Input

輸入文件short.in,共有n+m+3行,其中:
第一行爲一個整數n。
第2行到第n+1行(共n行),每行的兩個整數x和y,描述一個點的座標(以一個空格隔開)。
第n+2行爲一個整數m,表示圖中的連線個數。
此後的m行,每行描述一條連線,由兩個整數I,j組成,表示第i個點和第j個點之間有連線。
最後一行:兩個整數s和t,分別表示源點和目標點。


Output

輸出文件short.out僅一行,一個實數(保留兩位小數),表示從S到T的最短路徑的長度。


Sample Input

5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5


Sample Output

3.41


解析

本題解使用的是 Floyed算法

瞭解Floyed算法

Floyed算法的核心思想:

通過一個圖的權值矩陣求出它的每兩點間的最短路徑矩陣。
從圖的帶權鄰接矩陣A=[a(i,j)] n×n開始,遞歸地進行n次更新,即由矩陣D(0)=A,按一個公式,構造出矩陣D(1);又用同樣地公式由D(1)構造出D(2);……;最後又用同樣的公式由D(n-1)構造出矩陣D(n)。矩陣D(n)的i行j列元素便是i號頂點到j號頂點的最短路徑長度,稱D(n)爲圖的距離矩陣,同時還可引入一個後繼節點矩陣path來記錄兩點間的最短路徑。
採用鬆弛技術(鬆弛操作),對在i和j之間的所有其他點進行一次鬆弛。所以時間複雜度爲O(n^3);

------------------------------------------------------------------------------------------------------------------------------------(分割線)
說了一堆亂七八糟難以理解的東西,其實這道題就是一個很直板的 -模板題- ,但有一些細節要注意,自己一個人很難找到錯誤的地方,所以要小心慎行。


代碼

#include<cmath>
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
double g[101][101],c[101],x[101];
int n,m,a,d,s,t;
bool b[101];
int main() {
	memset(g,0x7f,sizeof(g)); //初始化數組g,給他賦最大值。(一定不要漏掉!!!)
    scanf("%d",&n); //n個點
    for(int i=1;i<=n;i++)scanf("%lf%lf",&c[i],&x[i]); //輸入n個點的座標
    scanf("%d",&m); //有m條邊
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&d);
		g[a][d]=sqrt(abs((c[a]-c[d]))*abs((c[a]-c[d]))+abs((x[a]-x[d]))*abs((x[a]-x[d]))); //利用勾股定理來計算距離
		g[d][a]=g[a][d];
    }
    scanf("%d%d",&s,&t); //輸入目標點
    for(int k=1;k<=n;k++) //Floyed算法
       for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
             if((i!=j) and (i!=k) and (j!=k) and (g[i][k]+g[k][j]<g[i][j]))
              g[i][j]=g[i][k]+g[k][j]; 
    printf("%.2lf",g[s][t]); //保留兩位小數輸出
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章