在求最短路時,通過深搜和寬搜可以解決,但是使用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算法可以處理帶有負權邊(邊的值爲負數)的圖,
但不能處理帶有負權迴路(或者叫“負權環”)的圖