基本介紹
- 中文名:弗洛伊德算法
- 外文名:Floyd(Floyd-Warshall)
- 時間複雜度:O(n^3)
- 空間複雜度:O(n^2)
- 作用:求多源最短路徑,求傳遞閉包
- 別名:Roy-Warshall算法
簡介
核心思路
路徑矩陣
狀態轉移方程
算法過程
時間複雜度與空間複雜度
優缺點分析
算法描述
參考代碼
C語言
#include<stdio.h>#include<stdlib.h>#define max 1000000000int d[1000][1000],path[1000][1000];int main(){ int i,j,k,m,n; int x,y,z; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ d[i][j]=max; path[i][j]=j; } for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); d[x][y]=z; d[y][x]=z; } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(d[i][k]+d[k][j]<d[i][j]) { d[i][j]=d[i][k]+d[k][j]; path[i][j]=path[i][k]; } } for(i=1;i<=n;i++) for(j=1;j<=i;j++) if (i!=j) printf("%d->%d:%d\n",i,j,d[i][j]); int f, en; scanf("%d%d",&f,&en); while (f!=en) { printf("%d->",f); f=path[f][en]; } printf("%d\n",en); return 0;}
C++語言
#include<iostream>#include<vector>using namespace std;const int &INF=100000000;void floyd(vector<vector<int> > &distmap,//可被更新的鄰接矩陣,更新後不能確定原有邊 vector<vector<int> > &path)//路徑上到達該點的中轉點//福利:這個函式沒有用除INF外的任何全局量,可以直接複製!{ const int &NODE=distmap.size();//用鄰接矩陣的大小傳遞頂點個數,減少參數傳遞 path.assign(NODE,vector<int>(NODE,-1));//初始化路徑數組 for(int k=1; k!=NODE; ++k)//對於每一個中轉點 for(int i=0; i!=NODE; ++i)//枚舉源點 for(int j=0; j!=NODE; ++j)//枚舉終點 if(distmap[i][j]>distmap[i][k]+distmap[k][j])//不滿足三角不等式 { distmap[i][j]=distmap[i][k]+distmap[k][j];//更新 path[i][j]=k;//記錄路徑 }}void print(const int &beg,const int &end, const vector<vector<int> > &path)//傳引用,避免拷貝,不占用記憶體空間 //也可以用棧結構先進後出的特性來代替函式遞歸 { if(path[beg][end]>=0) { print(beg,path[beg][end],path); print(path[beg][end],end,path); } else cout<<"->"<<end;}int main(){ int n_num,e_num,beg,end;//含義見下 cout<<"(不處理負權迴路)輸入點數、邊數:"; cin>>n_num>>e_num; vector<vector<int> > path, distmap(n_num,vector<int>(n_num,INF));//默認初始化鄰接矩陣 for(int i=0,p,q; i!=e_num; ++i) { cout<<"輸入第"<<i+1<<"條邊的起點、終點、長度(100000000代表無窮大,不聯通):"; cin>>p>>q; cin>>distmap[p][q]; } floyd(distmap,path); cout<<"計算完畢,可以開始查詢,請輸入出發點和終點:"; cin>>beg>>end; cout<<"最短距離為"<<distmap[beg][end]<<",列印路徑:"<<beg; print(beg,end,path);}
Matlab原始碼
function Floyd(w,router_direction,MAX)%w為此圖的距離矩陣%router_direction為路由類型:0為前向路由;非0為回溯路由%MAX是數據輸入時的∞的實際值len=length(w);flag=zeros(1,len);%根據路由類型初始化路由表R=zeros(len,len);for i=1:lenif router_direction==0%前向路由R(:,i)=ones(len,1)*i;else %回溯路由R(i,:)=ones(len,1)*i;endR(i,i)=0;enddisp('');disp('w(0)');dispit(w,0);disp('R(0)');dispit(R,1);%處理端點有權的問題for i=1:lentmp=w(i,i)/2;if tmp~=0w(i,:)=w(i,:)+tmp;w(:,i)=w(:,i)+tmp;flag(i)=1;w(i,i)=0;endend%Floyd算法具體實現過程for i=1:lenfor j=1:lenif j==i || w(j,i)==MAXcontinue;endfor k=1:lenif k==i || w(j,i)==MAXcontinue;endif w(j,i)+w(i,k)<w(j,k) %Floyd算法核心代碼w(j,k)=w(j,i)+w(i,k);if router_direction==0%前向路由R(j,k)=R(j,i);else %回溯路由R(j,k)=R(i,k);endendendend%顯示每次的計算結果disp(['w(',num2str(i),')'])dispit(w,0);disp(['R(',num2str(i),')'])dispit(R,1);end%中心和中點的確定[Center,index]=min(max(w'));disp(['中心是V',num2str(index)]);[Middle,index]=min(sum(w'));disp(['中點是V',num2str(index)]);endfunction dispit(x,flag)%x:需要顯示的矩陣%flag:為0時表示顯示w矩陣,非0時表示顯示R矩陣len=length(x);s=[];for j=1:lenif flag==0s=[s sprintf('%5.2f\t',x(j,:))];elses=[s sprintf('%d\t',x(j,:))];ends=[s sprintf('\n')];enddisp(s);disp('---------------------------------------------------');end% 選擇後按Ctrl+t取消注釋號%%% 示例:% a=[% 0,100,100,1.2,9.2,100,0.5;% 100,0,100,5,100,3.1,2;% 100,100,0,100,100,4,1.5;% 1.2,5,100,0,6.7,100,100;% 9.2,100,100,6.7,0,15.6,100;% 100,3.1,4,100,15.6,0,100;% 0.5,2,1.5,100,100,100,0% ];%% b=[% 0,9.2,1.1,3.5,100,100;% 1.3,0,4.7,100,7.2,100;% 2.5,100,0,100,1.8,100;% 100,100,5.3,0,2.4,7.5;% 100,6.4,2.2,8.9,0,5.1;% 7.7,100,2.7,100,2.1,0% ];%% Floyd(a,1,100)% Floyd(b,1,100)
pascal語言
program floyd;varst,en,f:integer;k,n,i,j,x:integer;a:array[1..10,1..10] of integer;path:array[1..10,1..10] of integer;beginreadln(n);for i:=1 to n dobeginfor j:=1 to n dobeginread(k);if k<>0 thena[i,j]:=kelsea[i,j]:=maxint;path[i,j]:=j;end;readln;end;for x:=1 to n dofor i:=1 to n dofor j:=1 to n doif a[i,j]>a[i,x]+a[x,j] thenbegina[i,j]:=a[i,x]+a[x,j];path[i,j]:=path[i,x];end;readln(st,en);writeln(a[st,en]);f:=st;while f<> en dobeginwrite(f);write('-->');f:=path[f,en];end;writeln(en);end.
java語言
//以無向圖G為入口,得出任意兩點之間的路徑長度length[i][j],路徑path[i][j][k],//途中無連線得點距離用0表示,點自身也用0表示public class FLOYD {int[][] length = null;// 任意兩點之間路徑長度int[][][] path = null;// 任意兩點之間的路徑public FLOYD(int[][] G) {int MAX = 100;int row = G.length;// 圖G的行數int[][] spot = new int[row][row];// 定義任意兩點之間經過的點int[] onePath = new int[row];// 記錄一條路徑length = new int[row][row];path = new int[row][row][];for (int i = 0; i < row; i++)// 處理圖兩點之間的路徑for (int j = 0; j < row; j++) {if (G[i][j] == 0)G[i][j] = MAX;// 沒有路徑的兩個點之間的路徑為默認最大if (i == j)G[i][j] = 0;// 本身的路徑長度為0}for (int i = 0; i < row; i++)// 初始化為任意兩點之間沒有路徑for (int j = 0; j < row; j++)spot[i][j] = -1;for (int i = 0; i < row; i++)// 假設任意兩點之間的沒有路徑onePath[i] = -1;for (int v = 0; v < row; ++v)for (int w = 0; w < row; ++w)length[v][w] = G[v][w];for (int u = 0; u < row; ++u)for (int v = 0; v < row; ++v)for (int w = 0; w < row; ++w)if (length[v][w] > length[v][u] + length[u][w]) {length[v][w] = length[v][u] + length[u][w];// 如果存在更短路徑則取更短路徑spot[v][w] = u;// 把經過的點加入}for (int i = 0; i < row; i++) {// 求出所有的路徑int[] point = new int[1];for (int j = 0; j < row; j++) {point[0] = 0;onePath[point[0]++] = i;outputPath(spot, i, j, onePath, point);path[i][j] = new int[point[0]];for (int s = 0; s < point[0]; s++)path[i][j][s] = onePath[s];}}}void outputPath(int[][] spot, int i, int j, int[] onePath, int[] point) {// 輸出i// 到j// 的路徑的實際代碼,point[]記錄一條路徑的長度if (i == j)return;if (spot[i][j] == -1)onePath[point[0]++] = j;// System.out.print(" "+j+" ");else {outputPath(spot, i, spot[i][j], onePath, point);outputPath(spot, spot[i][j], j, onePath, point);}}public static void main(String[] args) {int data[][] = {{ 0, 27, 44, 17, 11, 27, 42, 0, 0, 0, 20, 25, 21, 21, 18, 27, 0 },// x1{ 27, 0, 31, 27, 49, 0, 0, 0, 0, 0, 0, 0, 52, 21, 41, 0, 0 },// 1{ 44, 31, 0, 19, 0, 27, 32, 0, 0, 0, 47, 0, 0, 0, 32, 0, 0 },// 2{ 17, 27, 19, 0, 14, 0, 0, 0, 0, 0, 30, 0, 0, 0, 31, 0, 0 },// 3{ 11, 49, 0, 14, 0, 13, 20, 0, 0, 28, 15, 0, 0, 0, 15, 25, 30 },// 4{ 27, 0, 27, 0, 13, 0, 9, 21, 0, 26, 26, 0, 0, 0, 28, 29, 0 },// 5{ 42, 0, 32, 0, 20, 9, 0, 13, 0, 32, 0, 0, 0, 0, 0, 33, 0 },// 6{ 0, 0, 0, 0, 0, 21, 13, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0 },// 7{ 0, 0, 0, 0, 0, 0, 0, 19, 0, 11, 20, 0, 0, 0, 0, 33, 21 },// 8{ 0, 0, 0, 0, 28, 26, 32, 0, 11, 0, 10, 20, 0, 0, 29, 14, 13 },// 9{ 20, 0, 47, 30, 15, 26, 0, 0, 20, 10, 0, 18, 0, 0, 14, 9, 20 },// 10{ 25, 0, 0, 0, 0, 0, 0, 0, 0, 20, 18, 0, 23, 0, 0, 14, 0 },// 11{ 21, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 27, 22, 0, 0 },// 12{ 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0 },// 13{ 18, 41, 32, 31, 15, 28, 0, 0, 0, 29, 14, 0, 22, 0, 0, 11, 0 },// 14{ 27, 0, 0, 0, 25, 29, 33, 0, 33, 14, 9, 14, 0, 0, 11, 0, 9 },// 15{ 0, 0, 0, 0, 30, 0, 0, 0, 21, 13, 20, 0, 0, 0, 0, 9, 0 } // 16};for (int i = 0; i < data.length; i++)for (int j = i; j < data.length; j++)if (data[i][j] != data[j][i])return;FLOYD test=new FLOYD(data);for (int i = 0; i < data.length; i++)for (int j = i; j < data[i].length; j++) {System.out.println();System.out.print("From " + i + " to " + j + " path is: ");for (int k = 0; k < test.path[i][j].length; k++)System.out.print(test.path[i][j][k] + " ");System.out.println();System.out.println("From " + i + " to " + j + " length :"+ test.length[i][j]);}}}