1. 程式人生 > >floyd最小環 詳細講解

floyd最小環 詳細講解

轉載自:http://m.blog.csdn.net/blog/qq909157370/9225109#

注意!這裡寫成   #define data 0x3f3f3f3f  memset(map,data,sizeof(map))是wrong 按理來說應該不錯,鬱悶,以後還是迴圈賦值然後巨集定義#define data 100000000Problem Description

杭州有N個景區,景區之間有一些雙向的路來連線,現在8600想找一條旅遊路線,這個路線從A點出發並且最後回到A點,假設經過的路線為V1,V2,....VK,V1,那麼必須滿足K>2,就是說至除了出發點以外至少要經過2個其他不同的景區,而且不能重複經過同一個景區。現在

8600需要你幫他找一條這樣的路線,並且花費越少越好。

Input

第一行是2個整數NMN <= 100, M <= 1000),代表景區的個數和道路的條數。接下來的M行裡,每行包括3個整數a,b,c.代表ab之間有一條通路,並且需要花費c(c <= 100)

Output

對於每個測試例項,如果能找到這樣一條路線的話,輸出花費的最小值。如果找不到的話,輸出"It's impossible.".

Sample Input

3 3 1 2 1 2 3 1 1 3 1 3 3 1 2 1 1 2 3 2 3 1

Sample Output

3 It's impossible.

  對於找最小環,而且要經過至少兩個節點,權值和最小,演算法是floyd,但該注意和理解的地方實在很多   1.定義和理解:轉自    在圖論中經常會遇到這樣的問題,在一個有向圖裡,求出任意兩個節點之間的最短距離。我們在離散數學、資料結構課上都遇到過這個問題,在計算機網路裡介紹網路層的時候好像也遇到過這個問題,記不請了... 但是書本上一律採取的是Dijkstra演算法,通過Dijkstra演算法可以求出單源最短路徑,然後逐個節點利用Dijkstra演算法就可以了。不過在這裡想換換口味,採取Robert Floyd提出的演算法來解決這個問題。下面讓我們先把問題稍微的形式化一下:

     如果有一個矩陣D=[d(ij)],其中d(ij)>0表示i城市到j城市的距離。若ij之間無路可通,那麼d(ij)就是無窮大。又有d(ii)=0。編寫一個程式,通過這個距離矩陣D,把任意兩個城市之間的最短與其行徑的路徑找出來。     我們可以將問題分解,先找出最短的距離,然後在考慮如何找出對應的行進路線。如何找出最短路徑呢,這裡還是用到動態規劃的知識,對於任何一個城市而言,ij的最短距離不外乎存在經過ij之間的k和不經過k兩種可能,所以可以令k=123...n(n是城市的數目),在檢查d(ij)d(ik)+d(kj)的值;在此d(ik)d(kj)分別是目前為止所知道的ikkj的最短距離,因此d(ik)+d(kj)就是ij經過k的最短距離。所以,若有d(ij)>d(ik)+d(kj),就表示從i出發經過k再到j的距離要比原來的ij距離短,自然把ijd(ij)重寫為d(ik)+d(kj)每當一個k查完了,d(ij)就是目前的ij的最短距離。重複這一過程,最後當查完所有的k時,d(ij)裡面存放的就是ij之間的最短距離了。所以我們就可以用三個for迴圈把問題搞定了,但是有一個問題需要注意,那就是for迴圈的巢狀的順序:我們可能隨手就會寫出這樣的程式,但是仔細考慮的話,會發現是有問題的。

                     for(int i=0; i<n; i++)                           for(int j=0; j<n; j++)                                for(int k=0; k<n; k++)   

     問題出在我們太早的把i-k-j的距離確定下來了,假設一旦找到了i-p-j最短的距離後,ij就相當處理完了,以後不會在改變了,一旦以後有使ij的更短的距離時也不能再去更新了,所以結果一定是不對的。所以應當象下面一樣來寫程式:

                   for(int k=0; k<n; k++)                         for(int i=0; i<n; i++)                              for(int j=0; j<n; j++)

    這樣作的意義在於固定了k,把所有ij而經過k的距離找出來,然後象開頭所提到的那樣進行比較和重寫,因為k是在最外層的,所以會把所有的ij都處理完後,才會移動到下一個k,這樣就不會有問題了,看來多層迴圈的時候,我們一定要當心,否則很容易就弄錯了。     接下來就要看一看如何找出最短路徑所行經的城市了,這裡要用到另一個矩陣P,它的定義是這樣的:p(ij)的值如果為p,就表示ij的最短行經為i->...->p->j,也就是說pij的最短行徑中的j之前的最後一個城市。P矩陣的初值為p(ij)=i。有了這個矩陣之後,要找最短路徑就輕而易舉了。對於ij而言找出p(ij),令為p,就知道了路徑i->...->p->j;再去找p(ip),如果值為qip的最短路徑為i->...->q->p;再去找p(iq),如果值為riq的最短路徑為i->...->r->q;所以一再反覆,到了某個p(it)的值為i時,就表示it的最短路徑為i->t,就會的到答案了,ij的最短行徑為i->t->...->q->p->j。因為上述的演算法是從終點到起點的順序找出來的,所以輸出的時候要把它倒過來。     但是,如何動態的回填P矩陣的值呢?回想一下,當d(ij)>d(ik)+d(kj)時,就要讓ij的最短路徑改為走i->...->k->...->j這一條路,但是d(kj)的值是已知的,換句話說,就是k->...->j這條路是已知的,所以k->...->j這條路上j的上一個城市(p(kj))也是已知的,當然,因為要改走i->...->k->...->j這一條路,j的上一個城市正好是p(kj)。所以一旦發現d(ij)>d(ik)+d(kj),就把p(kj)存入p(ij)

 2 對於程式碼的理解:

[cpp]copyprint?

#include<iostream>

#include<cstdio>

#include<cstring>

usingnamespace std;  

#define data 100000000

#define N 110

#define min(x,y) ((x)>(y)?(y):(x))

int map[N][N],dis[N][N];  

int n,m;  

10 void floyd()  

11 {  

12 int i,j,k,mina=data;  

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

14     {  

15 //因為路徑ij的情況只有經過k和不經過k,而要求從一個點至少經過兩個節點返回原點,k每次更新都會使dis[i][j]得到更新,而只有在更新了一次k之後才可以找minmin即是在dis[i][i]最短的情況下的求至少經過兩個點又回到該點的最小距離,所以ij的值都應該小於ki的值從1k-1,而j的值卻跟i的值相關,即i!=j,因為當i=j時,dis[i][j]不是無窮大,而是從i->j->i的值,這就會出現自環,這裡我定義自環為經過一個節點就返回原節點的節點,比如像1->2->1這樣min的值會不準確,這不是經過了兩個節點,所以下面第一個兩層迴圈可以有三種寫法,具體看程式碼

16 

17 //當要擴充第k個節點時,前k-1個節點已經用過,並且是用於更新最短路徑dis[i][j]這就是第二個兩層for迴圈,所以在更新k之前已經有一條最短路徑從i到達j,此時再來尋找另外一個從ij的路徑,map[j][k]+map[k][i],如果有的話則一定形成了從i回到i的環,比如 1->2值為12->3值為2,3->4值為3,4->1值為4,則第一次存在從13的最短路,再尋找時找到了14,43的路徑,則形成了環,而且是最小的,注意第一個迴圈中加上的值是map[j][k]map[k][i]的值,map的是值都是初始值,不會變化,而dis在不斷更新

18 for(i=1;i<k;i++)  

19         {  

20 for(j=i+1;j<k;j++)  

21             {  

22                 mina=min(dis[i][j]+map[j][k]+map[k][i],mina);  

23             }  

24         }  

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

26         {  

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

28             {  

29 if(dis[i][j]>(dis[i][k]+dis[k][j]))  

30                 dis[i][j]=dis[i][k]+dis[k][j];  

31             }  

32         }  

33     }  

34 if(mina<data)  

35     printf("%d\n",mina);  

36 else

37     printf("It's impossible.\n");  

38 }  

39 int main()  

40 {  

41 int a,b,c,i,j;  

42 while(scanf("%d%d",&n,&m)!=EOF)  

43     {  

44 for(i=0;i<=n;i++)  

45 for(j=0;j<=n;j++)  

46          {  

47              map[i][j]=data;  

48              dis[i][j]=data;  

49          }  

50 for(i=0;i<m;i++)  

51         {  

52             scanf("%d%d%d",&a,&b,&c);  

53 if(map[a][b]>c)  

54             {  

55                  map[a][b]=map[b][a]=c;  

56                  dis[a][b]=dis[b][a]=c;  

57             }  

58         }  

59         floyd();  

60     }  

相關推薦

floyd 詳細講解

轉載自:http://m.blog.csdn.net/blog/qq909157370/9225109# 注意!這裡寫成   #define data 0x3f3f3f3f  memset(map,data,sizeof(map))是wrong 按理來說應該不錯,鬱悶,以後還是迴圈賦值然

Sightseeing trip POJ - 1734 -Floyd

sig span 利用 pac href sin 有用 tar cpp POJ - 1734 思路 : Floyd 實質 dp ,優化掉了第三維. dp [ i ] [ j ] [ k ] 指的是前k個點優化後 i -> j 的最短路。 所以我們就可

多源短路·floyd && 演算法

其實我已經會了。。但今天寫錯了一次。。。。實在恐怖。。所以我決定還是深度解析這個floyd演算法 Floyd-warshall 1.擺出問題 先擺出最簡單問題,給你圖,詢問a,b求a,b間最短路 不會floyd的時候,,我是紮紮實實的對每個點求單源最短路。。。 後來學了fl

HDU - 6080 :度度熊保護村莊 (凸包,floyd)(VJ1900題達成)

pri div -a pac for main 之間 ret != pro:二維平面上,給定N個村莊。M個士兵駐守,把村莊圍住,現在我們想留下更多的士兵休息,使得剩下的士兵任然滿足圍住村莊。N,M<500; sol:即是要找一個最小的環,環把村莊圍住。 由於是環,

關於Floyd求解的問題

lin 自己 路徑 三個點 pos 紅色 ++i ont mem 最近學習了floyd的奇妙用處,求解最小環,自己的領悟寫在了紙上。 對於一個最小環,顯然至少要包含三個點(此處不把兩個點的回路稱之為環) 從大體上考慮的話,一定有一個點與左右兩側的點是直接連接的(即不經其他點

floyd

int inf cst 而是 不知道 為什麽 class include con hdu1599 floyd求最小環 其實floyd求最小環就相當於找出一個一條只包括1到k-1中節點的路徑,然後把這個路徑與k這個節點相連。這樣是正確的原因是,最小環中一定有一個最大節點k,當

弗洛伊德Floyd

lse urn view ide 不存在 eps 圖片 none 枚舉 模板: #include<bits/stdc++.h> using namespace std; const int MAXN = 110; const int IN

2018.09.15 poj1734Sightseeing trip(floyd

跟hdu1599差不多.。 只是需要輸出方案。 這個可以遞迴求解。 程式碼: #include<iostream> #include<cstdio> #include

floyd

每次列舉k時,列舉所有編號小於k的結點i,j(i≠j≠k),可以得出一個經過i,j,k的可行環:a[i][k]+a[k][j]+dist[i][j],即i到j的最短路加上i到k、j到k的直接距離(若兩點之間沒有邊則為∞)。可以證明,若i到j的最短路經過k,則這

floyd改進版求

最小環改進演算法的證明 設一個環中的最大結點為k(編號最大), 與他相連的兩個點為i, j, 這個環的最短長度為g[i][k]+g[k][j]+i到j的路徑中所有結點編號都小於k的最短路徑長度。 根據

Vijos - 最佳路線(Floyd+有向圖)

https://vijos.org/p/1423 題目描述 年久失修的賽道令國際汽聯十分不滿。汽聯命令主辦方立即對賽道進行調整,否則將取消其主辦權。主辦方當然必須馬上開始行動。 賽道測評人員經過了三天三夜的資料採集,選出了若干可以使用的道路和各道路行駛所需的時間。這些道路包括若干直道

Floyd演算法求圖

觀光旅遊Time Limit:1000MS  Memory Limit:65536K Total Submit:1 Accepted:0Description背景 Background   湖南師大附中

多源短路徑FloydFloyd【模板】

Floyd演算法:用來找出每對點之間的最短距離。圖可以是無向圖,也可以是有向圖,邊權可為正,也可以為負,唯一要求是不能有負環。 1.初始化:將Map[][]中的資料複製到Dist[][]中作為每對頂點

floyd求無向圖——poj1734

給定一個無向圖,求出圖中由 3個及以上個點構成的環的邊權和 中的最小值。(一個點不能遍歷多次)在floyd時,先迴圈k,然後是i和j,你會發現在每次進入一個新的k迴圈時,每一個d(i,j)都儲存著從i到j,只經歷了編號不超過k-1的節點的最短路、於是,min{d(i,j)+

hdu 1599 find the mincost route【floyd

find the mincost route Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3758   

poj 1734 Floyd算求有向圖的

題意:旅遊公司要開發一條新的路線 , 要求這是一個總路程儘可能短的環 , 並且不能只含兩個城市 , 除開起點外 , 不能重複走之前走過的城市 , 輸出這條路線? Floyd演算法求最小環 程式碼: //用floyd演算法 , 求有向圖的最小環 #include #include #include #i

101572I Import Spaghetti 】【floyd】【記錄路徑】

【連結】 【題意】  找最小環 【思路】   ffloyd跑一邊,記錄轉移路徑 【程式碼】 #include<bits/stdc++.h> using namespace std; const int maxn = 1004; const int

vijos 觀光旅遊 fl 呆詳看

view logs scan 最優 根據 ted 算法 以及 too 背景 湖南師大附中成為百年名校之後,每年要接待大批的遊客前來參觀。學校認為大力發展旅遊業,可以帶來一筆可觀的收入。 描述 學校裏面有N個景點。兩個景點之間可能直接有道路相連,用Dist[I,J]表示它的長

HDU 4370 0 or 1(spfa+思維建圖+計算

inf 計算 最小 star while arch mes targe space 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4370 題目大意:有一個n*n的矩陣Cij(1<=i,j<=n),要找到矩陣Xi

dijkstra求

std oss 距離 IT ace math 技術 scan closed 任意一個環的權值,我們都可以看成兩個有邊相連的結點i、j的直接距離加上i、j間不包含邊(邊i->j)的最短路徑。 求最短路徑我們第一個想到的就是Dijkstra算法。 而Dijkstra所求的