求最短路徑——DFS+Floyd演算法

未來首富發表於2020-12-13

1),深度或廣度優先搜尋演算法(解決單源最短路徑)
從起始結點開始訪問所有的深度遍歷路徑或廣度優先路徑,則到達終點結點的路徑有多條,取其中路徑權值最短的一條則為最短路徑。
2),弗洛伊德演算法(解決多源最短路徑):時間複雜度O(n3),空間複雜度O(n2)
基本思想:最開始只允許經過1號頂點進行中轉,接下來只允許經過1號和2號頂點進行中轉…允許經過1~n號所有頂點進行中轉,來不斷動態更新任意兩點之間的最短路程。即求從i號頂點到j號頂點只經過前k號點的最短路程。

分析如下:1,首先構建鄰接矩陣Floyd[n+1][n+1],假如現在只允許經過1號結點,求任意兩點間的最短路程,很顯然Floyd[i][j] = min{Floyd[i][j], Floyd[i][1]+Floyd[1][j]}
2,接下來繼續求在只允許經過1和2號兩個頂點的情況下任意兩點之間的最短距離,在已經實現了從i號頂點到j號頂點只經過前1號點的最短路程的前提下,現在再插入第2號結點,來看看能不能更新更短路徑,故只需在步驟1求得的Floyd[n+1][n+1]基礎上,進行Floyd[i][j] = min{Floyd[i][j], Floyd[i][2]+Floyd[2][j]};…
3,很顯然,需要n次這樣的更新,表示依次插入了1號,2號…n號結點,最後求得的Floyd[n+1][n+1]是從i號頂點到j號頂點只經過前n號點的最短路程

#include<bits/stdc++.h>
#define nmax 1000
#define INF 99999999
using namespace std;
//鄰接矩陣儲存
int n,m,minPath, edge[nmax][nmax];//邊數,節點數,最短路徑,鄰接矩陣
int mark[nmax];//節點訪問標記

void dfs(int cur,int dis)//深搜找最短路徑,cur是節點數,dis是距離
{
    if(minPath<dis)
        return;//當前走過路徑大於之前最短路徑,沒必要再走下去
    if(cur==n){//節點數到達最大(臨界條件)
        if(minPath>dis)
            minPath=dis;//最後更新最短路徑
        return;//返回結束
    }
    else{
        for(int i=1;i<=n;i++){
            if(edge[cur][i]!=INF && edge[cur][i]!=0 && mark[i]==0 )//如果兩點之間有路徑且該點沒被訪問過
            {
                mark[i]=1;//標記訪問過;
                dfs(i,dis+edge[cur][i]);
                mark[i]=0;//最重要的一步!回溯完要重新標記
            }
        }
        return;
    }
}

int Floyd()//弗洛伊德演算法
{
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(edge[i][k]<INF && edge[k][j]<INF && edge[i][j]>edge[i][k]+edge[k][j])
                    //兩點到任意一點有距離,且經過中間點的距離小於兩點之間直接的距離
                    edge[i][j]=edge[i][k]+edge[k][j];//更新
            }
        }
    }

    return edge[1][n];
}

int main()
{
    while(cin >> n >> m && n != 0){
        //初始化鄰接矩陣
        int i, j;
        for(i = 1; i <= n; i++){
            for(j = 1; j <= n; j++){
                edge[i][j] = INF;
            }
            edge[i][i] = 0;
        }
        int a, b;
        while(m--){
            cin >> a >> b;
            cin >> edge[a][b];
        }
        //以dnf(1)為起點開始遞迴遍歷
        memset(mark, 0, sizeof(mark));
        minPath = INF;
        mark[1] = 1;
        dfs(1, 0);
        cout << minPath << endl;
    }
}

在這裡插入圖片描述

相關文章