Dijkstra算法幻枉,F(xiàn)loyd算法碰声,Prim算法,Kruskal算法

Dijkstra算法是貪心算法熬甫,是一個單源最短路算法胰挑,就是先記錄下從起始點到各個點的距離,然后選擇距離最小的結(jié)點椿肩,用這個最小距離加上選取的點和其他點一一比較瞻颂,看看需不需要更新起點到其他點的距離,直到所有的點選完郑象。

疑問:為什么要先選最小的點贡这?

按下圖排

如果先取小的排先是? #,10厂榛,#藕坯,30,100(把#當成是無窮大)

第二個結(jié)點的10最小噪沙,更新

得 #炼彪,10,60正歼,30辐马,100

接著是第四個結(jié)點30最小,更新

得 #局义,10喜爷,50,30萄唇,90

接著是第三個結(jié)點50最小檩帐,更新

得 #,10另萤,50湃密,30诅挑,60

最后由v5無更新,最終得#泛源,10拔妥,50,30达箍,60

如果取最大會怎么樣呢没龙?

原始序列:? #,10缎玫,#硬纤,30,100(把#當成是無窮大)

取100赃磨,無更新

取30筝家,由v4更新,得:

#煞躬,10,50逸邦,30恩沛,90

咦,我們發(fā)現(xiàn)在這一步就出現(xiàn)了問題缕减,

首先是多了50雷客,比30大這就不符合取最大的規(guī)則了桥狡,當然這不是最重要的搅裙,你可能會說,我可以選回去麻裹芝,但是先不說這在算法上可不可以實現(xiàn)部逮,它就算可以實現(xiàn)也是復(fù)雜的。

其次嫂易,第一步取最大這個情況下后面100變小了兄朋,它因為用后面的v4更新后變成了90,這會出現(xiàn)一種什么樣的問題呢怜械?這會讓第一步的比較無效颅和,試想會不會因為v0到v5的路徑變小了,導(dǎo)致v0到某個結(jié)點的距離要大于v0到v5再到某個結(jié)點的距離呢缕允?這是有可能的峡扩,當然在這個圖里面沒有這樣的結(jié)點,但這是有可能的障本,對吧教届?

這就是錯誤的點了。

小朋友,相信這時候你又有了疑問巍佑,什么疑問呢茴迁?那便是,為什么從最大更新后原來到最大距離的那個結(jié)點的距離會變小呢萤衰?

有點饒堕义,大概知道意思就好啦。

這便是因為有別的結(jié)點和源點的距離更小啊脆栋,在加上別的結(jié)點到v5結(jié)點的距離倦卖,是不是v0到v5的距離有可能會更小,有沒有這種可能椿争,有吧怕膛?

而換了從距離最小的那個結(jié)點開始比較更新,就不會有這個問題啦秦踪。

因為你想啊褐捻,如果別的結(jié)點和源點的距離更大,在加上別的結(jié)點到v5結(jié)點的距離椅邓,是不是v0到v5的距離不可能更小柠逞,不可能,對吧景馁?這就和前面的選擇不沖突了板壮。

我想到了一個有趣的事情,如果要求當源最長路合住,大概就是這樣反過來吧绰精。

Floyd多源最短路算法

假如現(xiàn)在只允許經(jīng)過1號頂點,求任意兩點之間的最短路程透葛,應(yīng)該如何求呢笨使?只需判斷e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是從i號頂點到j(luò)號頂點之間的路程僚害。e[i][1]+e[1][j]表示的是從i號頂點先到1號頂點阱表,再從1號頂點到j(luò)號頂點的路程之和。其中i是1~n循環(huán)贡珊,j也是1~n循環(huán)最爬,代碼實現(xiàn)如下。

for (i = 1; i <= n; i++)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? for (j = 1; j <= n; j++)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? if (e[i][j] > e[i][1] + e[1][j])

? ? ? ? ? ? ? ? ? ? ? ? e[i][j] = e[i][1] + e[1][j];

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

接下來繼續(xù)求在只允許經(jīng)過1和2號兩個頂點的情況下任意兩點之間的最短路程门岔。如何做呢爱致?我們需要在只允許經(jīng)過1號頂點時任意兩點的最短路程的結(jié)果下,再判斷如果經(jīng)過2號頂點是否可以使得i號頂點到j(luò)號頂點之間的路程變得更短寒随。即判斷e[i][2]+e[2][j]是否比e[i][j]要小糠悯,代碼實現(xiàn)為如下帮坚。

//經(jīng)過1號頂點

for(i=1;i<=n;i++)?

for(j=1;j<=n;j++)?

if (e[i][j] > e[i][1]+e[1][j])? e[i][j]=e[i][1]+e[1][j];?

//經(jīng)過2號頂點

for(i=1;i<=n;i++)?

for(j=1;j<=n;j++)?

if (e[i][j] > e[i][2]+e[2][j])? e[i][j]=e[i][2]+e[2][j];

最后允許通過所有頂點作為中轉(zhuǎn)

整個算法過程雖然說起來很麻煩,但是代碼實現(xiàn)卻非常簡單互艾,核心代碼只有五行:

for(k=1;k<=n;k++)

? ? for(i=1;i<=n;i++)?

? ? for(j=1;j<=n;j++)?

? ? if(e[i][j]>e[i][k]+e[k][j])?

? ? ? ? ? ? ? ? ? ? e[i][j]=e[i][k]+e[k][j];

這段代碼的基本思想就是:最開始只允許經(jīng)過1號頂點進行中轉(zhuǎn)试和,接下來只允許經(jīng)過1和2號頂點進行中轉(zhuǎn)……允許經(jīng)過1~n號所有頂點進行中轉(zhuǎn),求任意兩點之間的最短路程纫普。用一句話概括就是:從i號頂點到j(luò)號頂點只經(jīng)過前k號點的最短路程阅悍。

另外需要注意的是:Floyd-Warshall算法不能解決帶有“負權(quán)回路”(或者叫“負權(quán)環(huán)”)的圖,因為帶有“負權(quán)回路”的圖沒有最短路昨稼。例如下面這個圖就不存在1號頂點到3號頂點的最短路徑节视。因為1->2->3->1->2->3->…->1->2->3這樣路徑中,每繞一次1->-2>3這樣的環(huán)假栓,最短路就會減少1寻行,永遠找不到最短路。其實如果一個圖中帶有“負權(quán)回路”那么這個圖則沒有最短路匾荆。

看了這里拌蜘,首先有一個疑問:怎么這個三重循環(huán)的兩個節(jié)點之間只更新了1次?只能有兩段邊或者是一段邊的情況么牙丽?顯然不是的简卧。

為什么不是呢?我們先一個個分析剩岳,當k中轉(zhuǎn)站只有一個的時候贞滨,顯然是這樣的入热。但是當k有多個的時候就不是這樣子的了拍棕。

為啥不是呢?我看著這個循環(huán)就像只更了一次啊勺良。

小朋友绰播,那你有木有注意到它里面也是有兩個循環(huán)滴,好像不好理解喔尚困。

更新就更新蠢箩,你用兩個循環(huán)是啥意思呢?

這就是問題的切入點了事甜。

這我們只能從每一個循環(huán)開始看谬泌,假如只允許一個結(jié)點進行中轉(zhuǎn),e[i][j]表示的是從i號頂點到j(luò)號頂點之間的路程逻谦。e[i][1]+e[1][j]表示的是從i號頂點先到1號頂點掌实,再從1號頂點到j(luò)號頂點的路程之和。而兩重循環(huán)把n個頂點之間的聯(lián)系都遍歷了一遍邦马,可以得出是否需要經(jīng)過中轉(zhuǎn)最短贱鼻。

我們可以假設(shè)有4個頂點宴卖,v1,v2,v3,v4.。

把v1看成是中轉(zhuǎn)的頂點v2到v3的最短路為2 1 3

v2到v4的最短路為2 4

如果把v3變成是可以中轉(zhuǎn)的頂點邻悬,是不是有這樣子的可能症昏,v2到v4之間的最短路可以是 2 1 3 4,有這種可能父丰,對吧肝谭?

那這在兩個兩重循環(huán)里面是怎么體現(xiàn)的呢?一個兩重循環(huán)可以理解础米,那兩個分苇,n個要怎么理解呢?

從兩個開始說起吧屁桑,我們需要理解兩個頂點之間是怎么出現(xiàn)3條邊和兩個頂點的医寿。

以我們上面說的四個結(jié)點為例子,首先蘑斧,把v1當成是中轉(zhuǎn)站靖秩,e[2][3]=e[2][1]+e[1][3],沒問題竖瘾,對吧沟突。

進入到第二個二重循環(huán),把v3加入作為中轉(zhuǎn)站捕传,e[2][4]=e[2][3]+e[3][4]惠拭,再把e[2][3]展開就對了。

這就是最外層循環(huán)和里面兩重循環(huán)的聯(lián)系了庸论,外面的循環(huán)將里面的兩重循環(huán)后的值發(fā)生了變化职辅,一直變化著,一步步迭代更新聂示。

小朋友域携,你好像又有了新的疑問,那個鱼喉,為什么單源最短路需要從和源點距離最短的的結(jié)點開始選擇秀鞭,而這種算法卻不用把中轉(zhuǎn)結(jié)點也這樣子選更新的結(jié)點呢?

哎扛禽,其實是不一樣的锋边,哪里不一樣呢?

首先编曼,你有沒有發(fā)現(xiàn)豆巨,Dijkstra算法里面的v0(源點)并不是中轉(zhuǎn)點,Dijkstra算法的中轉(zhuǎn)點是從和源點距離最短的的結(jié)點開始遞增地一個個選擇的灵巧,這就讓它的中轉(zhuǎn)點不能亂選搀矫,不然可能前面的選擇就無效了(前面已經(jīng)分析過了)抹沪。

而為什么Floyd算法就可以亂選呢?首先它的中轉(zhuǎn)點是確定的瓤球,再隨意選擇源點和終點融欧,當也不是隨意的,因為最后它都會把所有的源點和終點通過兩重循環(huán)選完卦羡。

而它們兩兩之間在每個二重循環(huán)里面是不沖突的噪馏,因為只有一個中轉(zhuǎn)點。

如果加入了中轉(zhuǎn)點绿饵,它也是不沖突的欠肾,它一遍遍地更新了最短路。

你可能會想拟赊,你前面舉的例子的終點改變了(把3改成了4)刺桃,那如果不變呢?

好吸祟,我們來看不變的情況瑟慈。我們用v3作為第一個中轉(zhuǎn)的結(jié)點

e[2][7]=e[2][3]+e[3][7]假設(shè)更新了,經(jīng)過v3是2到7的最短路屋匕。

再加上v4作為中轉(zhuǎn)葛碧,我們發(fā)現(xiàn)它也是不沖突的。

我們可以對e[3][7]進行更新过吻,也可以對e[2][7]=e[2][4]+e[4][7]進行更新进泼。

哇,你可能會想纤虽,哇乳绕,它變了,可能沖突了哇廓推。

可系刷袍,真的嗎翩隧?

反正怪怪的樊展。

其實沒有的,先是可能e[2][7]=e[2][3]+e[3][7]堆生,然后可能更新為e[2][7]=e[2][4]+e[4][7]

沖突在哪里专缠?沒有吧,這個算法只是窮舉了所有的情況淑仆。

你可能還有一個問題涝婉,這是什么破算法,我直接用Dijkstra算法遍歷n次來不就完了嗎蔗怠?

額墩弯,問題是不一定好啊吩跋,而且想把復(fù)雜度降下來,程序?qū)懫饋磉€蠻復(fù)雜的渔工。后面有時間再想吧锌钮。

好了,吐血三升引矩,一個三個循環(huán)的算法梁丘,居然想了半天,罷遼旺韭,罷遼氛谜,還有問題也不想遼。

注意:如果兩個頂點之間沒有邊的話区端,應(yīng)該定義為正無窮值漫,后面才能慢慢變小。


Prim算法也是貪心算法來著织盼,是從頂點開始選取的惭嚣,這和kruskal算法有很大區(qū)別。



Kruskal算法悔政,將森林合并成樹晚吞。起始的每個結(jié)點它也當成是一個樹。先把所有權(quán)重的邊都選出來(因為是森林谋国,所以不能只取一邊) 槽地,不構(gòu)成回路就行,直到 ?? V-1條邊和邊集合中沒了元素芦瘾,構(gòu)成回路的邊扔掉捌蚊。

簡單說,就是不斷地把最小邊選出來近弟,并且不能構(gòu)成回路缅糟,最后選到V-1條邊就沒了,再選就一定會構(gòu)成回路祷愉。這就能將多個結(jié)點并成一棵樹了窗宦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末二鳄,一起剝皮案震驚了整個濱河市赴涵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌订讼,老刑警劉巖髓窜,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欺殿,居然都是意外死亡寄纵,警方通過查閱死者的電腦和手機鳖敷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來程拭,“玉大人哄陶,你說我怎么就攤上這事〔负” “怎么了屋吨?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長山宾。 經(jīng)常有香客問我至扰,道長,這世上最難降的妖魔是什么资锰? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任敢课,我火速辦了婚禮,結(jié)果婚禮上绷杜,老公的妹妹穿的比我還像新娘直秆。我一直安慰自己,他們只是感情好鞭盟,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布圾结。 她就那樣靜靜地躺著,像睡著了一般齿诉。 火紅的嫁衣襯著肌膚如雪筝野。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天粤剧,我揣著相機與錄音谤逼,去河邊找鬼捣炬。 笑死,一個胖子當著我的面吹牛拧烦,可吹牛的內(nèi)容都是我干的球切。 我是一名探鬼主播疯潭,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼嘱根,長吁一口氣:“原來是場噩夢啊……” “哼嚣潜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起梯醒,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤宽堆,失蹤者是張志新(化名)和其女友劉穎腌紧,沒想到半個月后茸习,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡壁肋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年号胚,在試婚紗的時候發(fā)現(xiàn)自己被綠了籽慢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡猫胁,死狀恐怖箱亿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弃秆,我是刑警寧澤届惋,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站菠赚,受9級特大地震影響脑豹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衡查,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一瘩欺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拌牲,春花似錦俱饿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至土居,卻和暖如春械拍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背装盯。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工坷虑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埂奈。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓迄损,卻偏偏與公主長得像,于是被迫代替她去往敵國和親账磺。 傳聞我的和親對象是個殘疾皇子芹敌,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容