1. 程式人生 > >最短路徑基礎演算法——弗洛伊德

最短路徑基礎演算法——弗洛伊德

問題 A(1171): 【基礎演算法】最短路徑問題 時間限制: 1 Sec 記憶體限制: 64 MB 題目描述 平面上有n個點(n<=100),每個點的座標均在-10000~10000之間。其中的一些點之間有連線。若有連線,則表示可從一個點到達另一個點,即兩點間有通路,通路的距離為兩點間的直線距離。現在的任務是找出從一點到另一點之間的最短路徑。 輸入 第1行:1個整數n 第2…n+1行:每行2個整數x和y,描述了一個點的座標 第n+2行:1個整數m,表示圖中連線的數量 接下來有m行,每行2個整數i和j,表示第i個點和第j個點之間有連線 最後1行:2個整數s和t,分別表示源點和目標點 輸出 第1行:1個浮點數,表示從s到t的最短路徑長度,保留2位小數(如果到達不了,輸出極大值0x7f對應的double型別的值) 樣例輸入 Copy (如果複製到控制檯無換行,可以先貼上到文字編輯器,再複製)

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

樣例輸出

3.41

思路點拔: 一道最短路的入門題,本題可以使用弗洛伊德演算法;下面我就詳細的推導一下弗洛伊德演算法 介紹 和Dijkstra演算法一樣,弗洛伊德(Floyd)演算法也是一種用於尋找給定的加權圖中頂點間最短路徑的演算法。該演算法名稱以創始人之一、1978年圖靈獎獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名。基本思想 通過Floyd計算圖G=(V,E)中各個頂點的最短路徑時,需要引入一個矩陣S,矩陣S中的元素a[i][j]表示頂點i(第i個頂點)到頂點j(第j個頂點)的距離。 假設圖G中頂點個數為N,則需要對矩陣S進行N次更新。初始時,矩陣S中頂點a[i][j]的距離為頂點i到頂點j的權值;如果i和j不相鄰,則a[i][j]=∞。 接下來開始,對矩陣S進行N次更新。第1次更新時,如果"a[i][j]的距離" > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示"i與j之間經過第1個頂點的距離"),則更新a[i][j]為"a[i][0]+a[0][j]"。 同理,第k次更新時,如果"a[i][j]的距離" > “a[i][k]+a[k][j]”,則更新a[i][j]為"a[i][k]+a[k][j]"。更新N次之後,操作完成! 單純的看上面的理論可能比較難以理解,下面通過例項來對該演算法進行說明。 例項分析

在這裡插入圖片描述 以上圖G4為例,來對弗洛伊德進行演算法演示。 在這裡插入圖片描述 初始狀態:S是記錄各個頂點間最短路徑的矩陣。 第1步:初始化S。 矩陣S中頂點a[i][j]的距離為頂點i到頂點j的權值;如果i和j不相鄰,則a[i][j]=∞。實際上,就是將圖的原始矩陣複製到S中。 注:a[i][j]表示矩陣S中頂點i(第i個頂點)到頂點j(第j個頂點)的距離。第2步:以頂點A(第1個頂點)為中介點,若a[i][j] > a[i][0]+a[0][j],則設定a[i][j]=a[i][0]+a[0][j]。 以頂點a[1]6,上一步操作之後,a[1][6]=∞;而將A作為中介點時,(B,A)=12,(A,G)=14,因此B和G之間的距離可以更新為26。同理,依次將頂點B,C,D,E,F,G作為中介點,並更新a[i][j]的大小。 程式碼實現

#include<cmath>
#include<cstdio>
#include<cstring>
const int maxn=105;
double jl(double a,double b,double c,double d) //兩點距離公式,注意座標是double 
{
    return sqrt(pow((a-b),2)+pow((c-d),2));
}
int main()
{
    int n,m,c,d,p,q;
    double a[maxn],b[maxn],dis[maxn][maxn]; //dis是鄰接矩陣 
    memset(dis,0x7f,sizeof(dis)); //將初值弄成極大值 
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%lf %lf",&a[i],&b[i]); //輸入每個點的座標 
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&c,&d); //輸入兩個相連的點 
        dis[c][d]=dis[d][c]=jl(a[c],a[d],b[c],b[d]); //拿到兩個點的距離,由於是無向圖,所以要對稱“儲存”
    } 
    scanf("%d %d",&p,&q);
    for(int k=1;k<=n;k++) //fluyd演算法,注意,k必須是最外層迴圈 
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i!=j&&i!=k&&j!=k) //更新 
                {
                    if(dis[i][j]>dis[i][k]+dis[k][j]) //動態規劃思想,記錄每一個階段的最小值 
                    {
                        dis[i][j]=dis[i][k]+dis[k][j];
                    }
                }
            }
        }
    }
    printf("%.2lf\n",dis[p][q]); //輸出結果 
    return 0;
}