1. 程式人生 > >最短路徑演算法(3)—Floyd(弗洛伊德)演算法

最短路徑演算法(3)—Floyd(弗洛伊德)演算法

Floyd-Warshall演算法,簡稱Floyd演算法,用於求解任意兩點間的最短距離,時間複雜度為O(n^3)

使用條件&範圍
通常可以在任何圖中使用,包括有向圖、帶負權邊的圖。

Floyd-Warshall 演算法用來找出每對點之間的最短距離。它需要用鄰接矩陣來儲存邊,這個演算法通過考慮最佳子路徑來得到最佳路徑。

1.注意單獨一條邊的路徑也不一定是最佳路徑。
2.從任意一條單邊路徑開始。所有兩點之間的距離是邊的權,或者無窮大,如果兩點之間沒有邊相連。
對於每一對頂點 u 和 v,看看是否存在一個頂點 w 使得從 u 到 w 再到 v 比己知的路徑更短。如果是更新它。
3.不可思議的是,只要按排適當,就能得到結果。

虛擬碼:

// dist(i,j) 為從節點i到節點j的最短距離
For i←1 to n do
   For j←1 to n do
      dist(i,j) = weight(i,j) 

For k←1 to n do // k為“媒介節點”
   For i←1 to n do
      For j←1 to n do
         if (dist(i,k) + dist(k,j) < dist(i,j)) then // 是否是更短的路徑?
            dist(i,j) = dist(i,k) + dist(k,j)

我們平時所見的Floyd演算法的一般形式

如下:

void Floyd(){
     int i,j,k;
     for(k=1;k<=n;k++)
         for(i=1;i<=n;i++)
             for(j=1;j<=n;j++)
                 if(dist[i][k]+dist[k][j]<dist[i][j])
                     dist[i][j]=dist[i][k]+dist[k][j];
}

注意下第6行這個地方,如果dist[i][k]或者dist[k][j]不存在,程式中用一個很大的數代替。最好寫成if(dist[i] [k]!=INF && dist[k][j]!=INF && dist[i][k]+dist[k][j]動畫演示Floyd演算法】。

程式碼說明幾點:

1、A[][]陣列初始化為各頂點間的原本距離,最後儲存各頂點間的最短距離。

2、path[][]陣列儲存最短路徑,與當前迭代的次數有關。初始化都為-1,表示沒有中間頂點。在求A[i][j]過程中,path[i][j]存放從頂點vi到頂點vj的中間頂點編號不大於k的最短路徑上前一個結點的編號。在演算法結束時,由二維陣列path的值回溯,可以得到從頂點vi到頂點vj的最短路徑。

初始化A[][]陣列為如下,即有向圖的鄰接矩陣。

這裡寫圖片描述

完整的實現程式碼如下:

#include <iostream>
#include <string>   
#include <stdio.h>   
using namespace std;   
#define MaxVertexNum 100   
#define INF 32767   
typedef struct  
{   
    char vertex[MaxVertexNum];   
    int edges[MaxVertexNum][MaxVertexNum];   
    int n,e;   
}MGraph;   

void CreateMGraph(MGraph &G)   
{   
    int i,j,k,p;   
    cout<<"請輸入頂點數和邊數:";   
    cin>>G.n>>G.e;   
    cout<<"請輸入頂點元素:";   
    for (i=0;i<G.n;i++)   
    {   
        cin>>G.vertex[i];   
    }   
    for (i=0;i<G.n;i++)   
    {   
        for (j=0;j<G.n;j++)   
        {   
            G.edges[i][j]=INF;   
            if (i==j)   
            {   
                G.edges[i][j]=0;   
            }   
        }   
    }      
    for (k=0;k<G.e;k++)   
    {   
        cout<<"請輸入第"<<k+1<<"條弧頭弧尾序號和相應的權值:";   
        cin>>i>>j>>p;   
        G.edges[i][j]=p;   
    }   
}   
void Dispath(int A[][MaxVertexNum],int path[][MaxVertexNum],int n);

void Floyd(MGraph G)
{
    int A[MaxVertexNum][MaxVertexNum],path[MaxVertexNum][MaxVertexNum];
    int i,j,k;
    for (i=0;i<G.n;i++)
    {
        for (j=0;j<G.n;j++)
        {
            A[i][j]=G.edges[i][j];
            path[i][j]=-1;
        }
    }
    for (k=0;k<G.n;k++)
    {
        for (i=0;i<G.n;i++)
        {
            for (j=0;j<G.n;j++)
            {
                if (A[i][j]>A[i][k]+A[k][j])
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=k;
                }
            }
        }
    }
    Dispath(A,path,G.n);
}

void Ppath(int path[][MaxVertexNum],int i,int j)
{
    int k;
    k=path[i][j];
    if (k==-1)
    {
        return;
    }
    Ppath(path,i,k);
    printf("%d,",k);
    Ppath(path,k,j);
}

void Dispath(int A[][MaxVertexNum],int path[][MaxVertexNum],int n)
{
    int i,j;
    for (i=0;i<n;i++)
    {
        for (j=0;j<n;j++)
        {
            if (A[i][j]==INF)
            {
                if (i!=j)
                {
                    printf("從%d到%d沒有路徑\n",i,j);
                }
            }
            else
            {
                printf("  從%d到%d=>路徑長度:%d路徑:",i,j,A[i][j]);
                printf("%d,",i);
                Ppath(path,i,j);
                printf("%d\n",j);
            }
        }
    }
}

int main()
{
    freopen("input2.txt", "r", stdin);
    MGraph G;
    CreateMGraph(G);
    Floyd(G);
    return 0;
}

測試結果如下:

這裡寫圖片描述

本文主要來至網上資料各種雜糅: