想必大家一定會floyd了吧,floyd只要暴力的三個for就可以出來,**好背,也好理解,但缺點就是時間複雜度高是o(n³)。
這個演算法所求的是單源最短路,好比說你寫好了dijkstra的函式,那麼只要輸入點a的編號,就可算出圖上每個點到這個點的距離。
561圖大概是這個樣子:2513
8231
2434
5725
2
我們以1為源點,來求所有點到一號點的最短路徑。
先建立乙個dis陣列,dis[i]表示第i號點到源點(1號點)的估計值,你可能會問為什麼是估計值,因為這個估計值會不斷更新,更新到一定次數就變成答案了,這個我們一會再說。
然後我們在建立乙個臨界矩陣,叫做:map,map[i][j]=v表示從i到j這條邊的權值是v。
dis初始值除了源點本身都是無窮大。源點本身都是0.
先從1號點開始。一號點,map[1][2]=5,一號點離2號點是5,比無窮大要小,所以dis[2]從無窮大變成了5。順便,我們用minn記錄距離1號點最短的點,留著以後會用。
dis[0,5,∞,∞,∞]。minn=2。
然後搜到3號點,map[1][3]=8,距離是8,比原來的dis[3]的∞小,於是dis[3]=8。但是8比dis[2]的5要大,所以minn不更新。
dis[0,5,8,∞,∞]
接著分別搜尋4,5號點,發現map[1][4],map[1][5]都是∞,所以就不更新。
現在,dis陣列所呈現的明顯不是最終答案,因為我們才更新一遍,現在我們開始第二次更新,第二次更新以什麼為開始呢?就是以上一次我們存下來的,minn,相當於把2當源點,求所有點到它的最短路,加上它到真正的源點(1號點)的距離,就是我們要求的最短路。
從2號點開始,搜尋3號點,map[2][3]=1,原本dis[3]=8,發現dis[2]+map[2][3]=5+1=6dis[0,5,6,∞,∞] minn=3.
然後搜尋4號點,map[2][4]=3,原本dis[4]=∞,所以,dis[2]+map[2][4]=5+3=81,minn不更新。
dis[0,5,6,8,∞] minn=3.
接著搜尋5號點,map[2][5]=2,5+2=7,7
dis[0,5,6,8,7]
三號點還是按照二號點的方法搜尋,發現沒有可以更新的,然後搜尋四號。
四號搜5號點,發現8+7>5+2,所以依然不更新,然後跳出迴圈。
現在的估計值就全部為確定值了:
dis[0,5,6,8,7]
這就是每個點到源點一號點的距離,我們來看一下**:
#include #include這就是用鄰接矩陣實現dijkstra,但是這個演算法有乙個壞處,就是出現負權邊,這個演算法就炸了,要解決負權邊,我以後會給大家帶來bell man ford(spfa)#include
#include
#include
#include
using
namespace
std;
int map[110][110];//
這就是map陣列,儲存圖
int dis[10010];//
dis陣列,儲存估計值
int book[10010];//
book[i]代表這個點有沒有被當做源點去搜尋過,1
為有,0為沒有。這樣就不會重複搜尋了。
intn,m;
void dijkstra(int u)//
主函式,引數是源點編號
for(int i=1;i<=n-1;i++)
book[start]=1
;
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[start]+map[start][j]);//
以新的點來更新dis。}}
intmain()
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)
map[i][j]=0
; dijkstra(
1);//以1為源點。
for(int i=1;i<=n;i++)
cout
}
這個演算法的複雜度是o(n²),空間複雜度也是n平方,如果用鄰接表來實現,最差情況,時間複雜度是o(n*m)似乎比n²要大一些,但是空間複雜度會從n平方變成m,少了很多,現在我呈上鄰接表的**。
#include #include一年多了,身為乙個oier,經歷了太多。#include
#include
#include
#include
using
namespace
std;
int value[10010],to[10010],next[10010
];int head[10010
],total;
int book[10010
];int dis[10010
];int
n,m;
void adl(int a,int b,int
c)void dijkstra(intu)}
intmain()
dijkstra(1);
for(int i=1;i<=n;i++)
cout
}
當年那麼畏懼的dijkstra、鄰接表,現在已經是信手拈來。
那個暑假,因為djkstra名字的朗朗上口,講自己名字改為了dijkstra,但是逐漸因為spfa的可處理負權邊,也將dijkstra,淡忘。
如今突然想起,加入了堆優化,有人說:一道題如果邊權沒有負數,那麼一定是在卡spfa。這時候就用到了堆優化的dijkstra。
一年前提到,樸素的dijkstra時間複雜度是n^2,被spfa的m*常數吊打,但是,經過堆優化,dijkstra的時間複雜度能達到nlogn,如果這個圖特別稠密的話,也就是m特別大(比如完全圖就是n^2),那麼nlogn是要小於m的,這就用到了dijkstra
首先堆優化怎麼優化?觀察上面的**,每次迴圈中都再巢狀乙個迴圈求dis值最小的點。這裡,我們可以用乙個優先佇列,每當搜尋到乙個新點,扔到優先佇列裡面,這樣每次就取隊首的絕對是最優值。這樣可以省去for迴圈。
#include #include#include
#include
#include
#include
#include
#define in(a) a=read()
#define rep(i,k,n) for(long long i=k;i<=n;i++)
#define maxn 10010
using
namespace
std;
typedef pair
long,long
long>p;
inline
long
long
read()
long
long
n,m,s;
long
long total=0,head[maxn],nxt[maxn<<10],to[maxn<<10],val[maxn<<10
];long
long
dis[maxn],vis[maxn];
priority_queue
,greater> q;//
優先佇列優化
inline void adl(long
long a,long
long b,long
long
c)inline
void
dijkstra()
}return;}
intmain()
Dijkstra 最短路徑演算法 秒懂詳解
想必大家一定會floyd了吧,floyd只要暴力的三個for就可以出來,好背,也好理解,但缺點就是時間複雜度高是o n 這個演算法所求的是單源最短路,好比說你寫好了dijkstra的函式,那麼只要輸入點a的編號,就可算出圖上每個點到這個點的距離。561 2513 8231 2434 5725 2圖大...
Dijkstra 最短路徑演算法 秒懂詳解
想必大家一定會floyd了吧,floyd只要暴力的三個for就可以出來,好背,也好理解,但缺點就是時間複雜度高是o n 這個演算法所求的是單源最短路,好比說你寫好了dijkstra的函式,那麼只要輸入點a的編號,就可算出圖上每個點到這個點的距離。5 6 1 2 5 1 3 8 2 3 1 2 4 3...
Dijkstra最短路徑演算法
基本思路是 選擇出發點相鄰的所有節點中,權最小的乙個,將它的路徑設定為確定。其他節點的路徑需要儲存起來。然後從剛剛確認的那個節點的相鄰節點,算得那些節點的路徑長。然後從所有未確定的節點中選擇乙個路徑最短的設定為確定。重複上面步驟即可。void dijkstra graph g,string v fl...