最短路徑-Floyd-Warshall算法

在求最短路時,通過深搜和寬搜可以解決,但是使用Floyd-Warshall會有更高的效率

只用五行代碼求最短路徑!!!

案例:a城市到b城市有許多公路,有些城市則沒有,爲了節約經費,求出a到b的最短路程
以下爲例,兩地路程用鄰接矩陣表示
在這裏插入圖片描述
試想通過以往的經驗,如果任意兩點(例如頂點a到頂點b)之間的距離路程縮短,只能引入第三個點(頂點k)並通過k中轉即a→k→b,才能縮短a到b的路程,那麼中轉1~n的哪一個點呢?甚至有時候不止通過一個點,而是經過兩個點或者多個點讓路程變得更短。

下面我們來將這個問題優化:

假如允許經過1號頂點時,只需要判斷e[i][1]+e[1][i]是否比e[i][j]要小即可,代碼實現代碼實現:

for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][1]+e[1][j]<e[i][j]){
				e[i][j]=e[i][1]+e[1][j];
			}
		}
	}

任意兩點之間最短路程更新爲:
在這裏插入圖片描述

在允許經過1和2號頂點情況下,代碼實現如下:

//經過1號頂點時 
	for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][1]+e[1][j]<e[i][j]){
				e[i][j]=e[i][1]+e[1][j];
			}
		}
	}
	//經過2號頂點時 
	for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][2]+e[2][j]<e[i][j]){
				e[i][j]=e[2][1]+e[2][j];
			}
		}
	}

在允許經過1和2號頂點情況下,任意兩點之間最短;路程更新爲:
在這裏插入圖片描述
在允許經過1和2、3號頂點情況下,任意兩點之間最短路程更新爲:
在這裏插入圖片描述
最後允許所有點中轉,最短路程更新爲:
在這裏插入圖片描述
代碼實現:

for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
		    for(int j=1j<=n;j++){
		    	if(e[i][k]+e[k][j]<e[i][j]){
			    	e[i][j]=e[i][k]+e[k][j];
		    	}
	    	}
    	}
	} 

這段代碼的基本思想是:最開始允許經過1號頂點進行,求任意兩點最短距離中轉,接下來只允許經過2號頂點進行中轉…允許1~n號頂點進行中轉
用一句話概括就是:從i號頂點到j號頂點只經過前k號頂點的最短路徑,其實是一種動態規劃的思想

完整代碼:

#include<cstdio>
int e[201][201],n,m,t1,t2,t3,a,b;
int main(){
	scanf("%d %d %d %d",&n,&m,&a,&b);
	//初始化矩陣 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j){
				e[i][j]=0;
			}else{
				e[i][j]=99999999;
			}
		}
		//讀入邊 
		for(int i=1;i<=m;i++){
			scanf("%d %d %d",&t1,&t2,&t3);
			e[t1][t2]=t3;
		}
	}
	//Floyd-Warshall算法核心代碼 
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
		    for(int j=1;j<=n;j++){
		    	if(e[i][k]+e[k][j]<e[i][j]){
			    	e[i][j]=e[i][k]+e[k][j];
		    	}
	    	}
    	}
	} 
	 
	printf("%d\n",e[a][b]);
	
	return 0;
} 

注意:-Floyd-Warshall算法可以處理帶有負權邊(邊的值爲負數)的圖,
但不能處理帶有負權迴路(或者叫“負權環”)的圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章