日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Floyd —Warshall(最短路及其他用法详解)

發(fā)布時間:2023/12/15 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Floyd —Warshall(最短路及其他用法详解) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、多元最短路求法

多元都求出來了,單源的肯定也能求。
思想是動態(tài)規(guī)劃的思想:從任意節(jié)點(diǎn)A到任意節(jié)點(diǎn)B的最短路徑不外乎2種可能,1是直接從A到B,2是從A經(jīng)過若干個節(jié)點(diǎn)X到B。所以,我們假設(shè)Dis(AB)為節(jié)點(diǎn)A到節(jié)點(diǎn)B的最短路徑的距離,對于每一個節(jié)點(diǎn)X,我們易寫出狀態(tài)轉(zhuǎn)移方程Dis(AB) =min(Dis(AX) + Dis(XB) ,Dis(AB))這樣一來,當(dāng)我們遍歷完所有節(jié)點(diǎn)X,Dis(AB)中記錄的便是A到B的最短路徑的距離。

memset(Dis,0x3f,sizeof(Dis); //初始化,這里采用0x3f而非0x7f,是當(dāng)兩個0x7f7f7f7f相加符號變號成為一個無窮小量。 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];}}}} }

這里一定要把K寫到外邊,需要先更新K前面的點(diǎn)在更新K后的點(diǎn)才有意義。

結(jié)合代碼 并參照上圖所示 我們來模擬執(zhí)行下 這樣才能加深理解:
第一關(guān)鍵步驟:當(dāng)k執(zhí)行到x,i=v,j=u時,計算出v到u的最短路徑要通過x,此時v、u聯(lián)通了。
第二關(guān)鍵步驟:當(dāng)k執(zhí)行到u,i=v,j=y,此時計算出v到y(tǒng)的最短路徑的最短路徑為v到u,再到y(tǒng)(此時v到u的最短路徑上一步我們已經(jīng)計算過來,直接利用上步結(jié)果)。
第三關(guān)鍵步驟:當(dāng)k執(zhí)行到y(tǒng)時,i=v,j=w,此時計算出最短路徑為v到y(tǒng)(此時v到y(tǒng)的最短路徑長在第二步我們已經(jīng)計算出來了),再從y到w。
依次掃描每一點(diǎn)(k),并以該點(diǎn)作為中介點(diǎn),計算出通過k點(diǎn)的其他任意兩點(diǎn)(i,j)的最短距離,這就是floyd算法的精髓!同時也解釋了為什么k點(diǎn)這個中介點(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è)置為0,聯(lián)通時設(shè)置為1.
則可得狀態(tài)轉(zhuǎn)移方程
dis[i][j]=dp[i][j]||(dp[i][k]&&dp[k][j]);
跟上面代碼除了狀態(tài)轉(zhuǎn)移方程之外還有初始化不同,這個都初始化為0;
其余都一樣。要么ij直接連通,要么ij通過K聯(lián)通。

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((dp[i][k]&&dp[k][j])&&!Dis[i][j]){Dis[i][j]=Dis[i][k]+Dis[k][j];path[i][j]=k;}}}} }

三、求無向圖中可以刪除一些邊,使得任意兩點(diǎn)的最短路不改變,求這些邊能刪除的最大的條數(shù)。(最小生成樹問題)

首先先在輸入邊的時候?qū)⒅剡吶サ?#xff0c;保留最小的。
然后進(jìn)行佛洛依德。
如果原來兩點(diǎn)的最短距離大于經(jīng)過第三個點(diǎn)的最短距離的話,那么我們就將這兩點(diǎn)的最短距離
替換成經(jīng)過第三條邊的最短距離,當(dāng)循環(huán)節(jié)結(jié)束后通過對比兩點(diǎn)之間的距離變化,即可知哪些邊將被刪去。但是~~~當(dāng)兩點(diǎn)之間本來沒有邊的情況下,我們肯定是經(jīng)過第三個點(diǎn)所到達(dá)的。那么就沒有替換原來的邊,這種情況的話,就直接continue;

四、無向圖最小環(huán)

若用dis[i][j]表示ij之間的最小值,則由i j 加線外一點(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的最短路上,則這個環(huán)中至少有三個點(diǎn),可得狀態(tài)轉(zhuǎn)移方程 ans=min(ans,dis[i][j]+length[i][k]+length[k][j]);

#include <cstdio> #include <cstring> #include <map> #include <queue> #include <algorithm>using namespace std;struct Node {int s[9];//s數(shù)組表示包括本端所連的fenceNode() {memset(s,0,sizeof(s));}bool operator < (const Node& a) const {for(int i=0;i<9;++i)if(s[i]<a.s[i])return true;else if(s[i]>a.s[i])return false;return false; }bool operator ==(const Node& a) const {for(int i=0;i<9;++i)if(s[i]!=a.s[i])return false;return true; }}fence[205]; int n,s,ls,ns,n1s,n2s,sta,des,cur; int g[105][105],cnt=0,dis[105][105]; bool vis[105]; map<Node,int> mp; int floyd() {int ans=0x1f1f1f1f;for(int i=1;i<=n;++i)for(int j=i;j<=n;++j)dis[i][j]=dis[j][i]=g[i][j];for(int k=1;k<=cnt;++k) {for(int i=1;i<k;++i)//尋找最小環(huán)for(int j=i+1;j<k;++j)if(dis[i][j]+g[i][k]+g[k][j]<ans)//由于此處會存在三個INF相加,所以INF設(shè)為0x1f1f1f1fans=dis[i][j]+g[i][k]+g[k][j]; for(int i=1;i<=n;++i)//更新最短路for(int j=1;j<=n;++j)if(dis[i][j]>dis[i][k]+dis[k][j])dis[i][j]=dis[i][k]+dis[k][j]; } return ans; } int main() {//freopen("fence6.in","r",stdin);// freopen("fence6.out","w",stdout);memset(g,0x1f,sizeof(g));scanf("%d",&n);for(int i=1;i<=n;++i) {//讀入邊數(shù)據(jù),并給每個點(diǎn)標(biāo)一個數(shù)scanf("%d%d%d%d",&s,&ls,&n1s,&n2s);fence[i<<1].s[8]=fence[(i<<1)|1].s[8]=s;while(n1s-->0)scanf("%d",&fence[i<<1].s[n1s]);sort(fence[i<<1].s,fence[i<<1].s+9);if(mp[fence[i<<1]]==0)mp[fence[i<<1]]=++cnt;while(n2s-->0)scanf("%d",&fence[(i<<1)|1].s[n2s]);sort(fence[(i<<1)|1].s,fence[(i<<1)|1].s+9);if(mp[fence[(i<<1)|1]]==0)mp[fence[(i<<1)|1]]=++cnt;sta=mp[fence[i<<1]];des=mp[fence[(i<<1)|1]];g[sta][des]=g[des][sta]=ls;//邊信息轉(zhuǎn)成點(diǎn)信息 } printf("%d\n",floyd()); return 0; }

五、傳遞閉包問題

鄰接矩陣是顯示兩點(diǎn)的直接關(guān)系,如a直接能到b,就為1。而傳遞閉包顯示的是傳遞關(guān)系,如a不能直接到c,卻可以通過a到b到d再到c,因此a到c為1。

另外矩陣A進(jìn)行自乘即A{2}得到的矩陣中,為1的值表示走最多兩步可以到達(dá)。A{3}矩陣中為1的值表示,最多走三步可以到達(dá)。
簡單來說,就是有向圖確定先后順序。

/* 題目:n頭牛進(jìn)行m場比賽,問能確定排名的有多少頭牛。解答:構(gòu)造一個n個點(diǎn)的有向圖,如果牛a勝b,那么a->b,如果a->b,b->c,則有a->c,這個用floyd。最后得到該圖的傳遞閉包link的二維數(shù)組。最后統(tǒng)計每一個點(diǎn)入度和出度和為n-1的點(diǎn)的個數(shù)即可。 */ #include<stdio.h> #include<string.h> const int MAX=105; /* 有向圖的傳遞閉包! 注意傳遞之前一定要初始化! 如果i!=j&&(i,j)不屬于E(邊的集合) t[i][j]=0; 如果i=j||(i,j)屬于E(邊的集合) t[i][j]=1; *///傳遞閉包 void Transitive_Closure(int n,bool t[][MAX]) {int i,j,k;for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)t[i][j]=t[i][j]|(t[i][k]&t[k][j]); } int main() {int n,i,j,m,st,ed,sum,num;bool t[MAX][MAX];while(scanf("%d%d",&n,&m)){if(n==0&&m==0)return 0;memset(t,false,sizeof(t));for(i=1;i<=n;i++)t[i][i]=true;for(i=1;i<=m;i++){scanf("%d%d",&st,&ed);t[st][ed]=true;}//上面的代碼都是初始化Transitive_Closure(n,t);sum=0;for(i=1;i<=n;i++){num=0;for(j=1;j<=n;j++)if(i==j)continue;elsenum+=(t[i][j]||t[j][i]);//統(tǒng)計出度和入度的個數(shù)!sum+=(num==n-1);}printf("%d\n",sum);}return 0; } /* 5 5 4 3 4 2 3 2 1 2 2 52 */

總結(jié)

以上是生活随笔為你收集整理的Floyd —Warshall(最短路及其他用法详解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。