Floyd —Warshall(最短路及其他用法详解)
一、多元最短路求法
多元都求出來(lái)了,單源的肯定也能求。
思想是動(dòng)態(tài)規(guī)劃的思想:從任意節(jié)點(diǎn)A到任意節(jié)點(diǎn)B的最短路徑不外乎2種可能,1是直接從A到B,2是從A經(jīng)過(guò)若干個(gè)節(jié)點(diǎn)X到B。所以,我們假設(shè)Dis(AB)為節(jié)點(diǎn)A到節(jié)點(diǎn)B的最短路徑的距離,對(duì)于每一個(gè)節(jié)點(diǎn)X,我們易寫(xiě)出狀態(tài)轉(zhuǎn)移方程Dis(AB) =min(Dis(AX) + Dis(XB) ,Dis(AB))這樣一來(lái),當(dāng)我們遍歷完所有節(jié)點(diǎn)X,Dis(AB)中記錄的便是A到B的最短路徑的距離。
這里一定要把K寫(xiě)到外邊,需要先更新K前面的點(diǎn)在更新K后的點(diǎn)才有意義。
結(jié)合代碼 并參照上圖所示 我們來(lái)模擬執(zhí)行下 這樣才能加深理解:
第一關(guān)鍵步驟:當(dāng)k執(zhí)行到x,i=v,j=u時(shí),計(jì)算出v到u的最短路徑要通過(guò)x,此時(shí)v、u聯(lián)通了。
第二關(guān)鍵步驟:當(dāng)k執(zhí)行到u,i=v,j=y,此時(shí)計(jì)算出v到y(tǒng)的最短路徑的最短路徑為v到u,再到y(tǒng)(此時(shí)v到u的最短路徑上一步我們已經(jīng)計(jì)算過(guò)來(lái),直接利用上步結(jié)果)。
第三關(guān)鍵步驟:當(dāng)k執(zhí)行到y(tǒng)時(shí),i=v,j=w,此時(shí)計(jì)算出最短路徑為v到y(tǒng)(此時(shí)v到y(tǒng)的最短路徑長(zhǎng)在第二步我們已經(jīng)計(jì)算出來(lái)了),再?gòu)膟到w。
依次掃描每一點(diǎn)(k),并以該點(diǎn)作為中介點(diǎn),計(jì)算出通過(guò)k點(diǎn)的其他任意兩點(diǎn)(i,j)的最短距離,這就是floyd算法的精髓!同時(shí)也解釋了為什么k點(diǎn)這個(gè)中介點(diǎn)要放在最外層循環(huán)的原因.
完整代碼:
#include<iostream> #include<stack> using namespace std; #define MAX 1000 int Graph[MAX][MAX]; int Dis[MAX][MAX]; #define infinite 1000 int path[MAX][MAX];void floyd(int N) {int i,j,k;for(k=0;k<N;k++){for(i=0;i<N;i++){for(j=0;j<N;j++){if(Dis[i][k]+Dis[k][j]<Dis[i][j]){Dis[i][j]=Dis[i][k]+Dis[k][j];path[i][j]=k;}}}}}void print_path(int N) {int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if((i!=j) &&Dis[i][j]!=infinite){cout<<i+1<<"----"<<j+1<<" distance:"<<Dis[i][j]<<endl;cout<<"path:"<<endl;int k=j;stack <int> ph;do{k=path[i][k];ph.push(k);}while(k!=i);cout<<ph.top()+1;ph.pop();while(!ph.empty()){cout<<"->"<<ph.top()+1;ph.pop();}cout<<"->"<<j+1<<endl;}}} }void main() {int N,i,j;cin>>N;for(i=0;i<N;i++){for(j=0;j<N;j++){int g;cin>>g;Graph[i][j]=g;Dis[i][j]=g;}} //初始化路徑for(i=0;i<N;i++){for(j=0;j<N;j++){path[i][j]=i;}}floyd(N);print_path(N);system("pause"); }二、連通性
講Dis[i][j]不連聯(lián)通時(shí)設(shè)置為0,聯(lián)通時(shí)設(shè)置為1.
則可得狀態(tài)轉(zhuǎn)移方程
dis[i][j]=dp[i][j]||(dp[i][k]&&dp[k][j]);
跟上面代碼除了狀態(tài)轉(zhuǎn)移方程之外還有初始化不同,這個(gè)都初始化為0;
其余都一樣。要么ij直接連通,要么ij通過(guò)K聯(lián)通。
三、求無(wú)向圖中可以刪除一些邊,使得任意兩點(diǎn)的最短路不改變,求這些邊能刪除的最大的條數(shù)。(最小生成樹(shù)問(wèn)題)
首先先在輸入邊的時(shí)候?qū)⒅剡吶サ?#xff0c;保留最小的。
然后進(jìn)行佛洛依德。
如果原來(lái)兩點(diǎn)的最短距離大于經(jīng)過(guò)第三個(gè)點(diǎn)的最短距離的話(huà),那么我們就將這兩點(diǎn)的最短距離
替換成經(jīng)過(guò)第三條邊的最短距離,當(dāng)循環(huán)節(jié)結(jié)束后通過(guò)對(duì)比兩點(diǎn)之間的距離變化,即可知哪些邊將被刪去。但是~~~當(dāng)兩點(diǎn)之間本來(lái)沒(méi)有邊的情況下,我們肯定是經(jīng)過(guò)第三個(gè)點(diǎn)所到達(dá)的。那么就沒(méi)有替換原來(lái)的邊,這種情況的話(huà),就直接continue;
四、無(wú)向圖最小環(huán)
若用dis[i][j]表示ij之間的最小值,則由i j 加線(xiàn)外一點(diǎn)k的環(huán)值為dis[i][j]+length[i][k]+length[k][j];
枚舉中間點(diǎn)k,在用其更新最短路前,先找最小環(huán),令1<=i<j<k,即k點(diǎn)必定不在i,j的最短路上,則這個(gè)環(huán)中至少有三個(gè)點(diǎn),可得狀態(tài)轉(zhuǎn)移方程 ans=min(ans,dis[i][j]+length[i][k]+length[k][j]);
五、傳遞閉包問(wèn)題
鄰接矩陣是顯示兩點(diǎn)的直接關(guān)系,如a直接能到b,就為1。而傳遞閉包顯示的是傳遞關(guān)系,如a不能直接到c,卻可以通過(guò)a到b到d再到c,因此a到c為1。
另外矩陣A進(jìn)行自乘即A{2}得到的矩陣中,為1的值表示走最多兩步可以到達(dá)。A{3}矩陣中為1的值表示,最多走三步可以到達(dá)。
簡(jiǎn)單來(lái)說(shuō),就是有向圖確定先后順序。
總結(jié)
以上是生活随笔為你收集整理的Floyd —Warshall(最短路及其他用法详解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 任意进制转化 函数 模板(一)
- 下一篇: USACO Training Secti