聲明:圖片及內容基於https://www.bilibili.com/video/BV1oa4y1e7Qt?from=articleDetail
多源最短路徑的引入
Floyd算法
原理
加入a:
加入b:
加入c:
數據結構
核心代碼
Floyd()
void MGraph::Floyd(){ for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ dist[i][j]=arc[i][j]; //dist數組初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist為INFINIT則無路徑,dist為0則指向自己
path[i][j]=vertex[i]+vertex[j]; //path數組初始化
else path[i][j]=""; //不符合則path為空串
} } for(int k=0;k<vertexNum;k++){ //k個頂點循環k次
for(int i=0;i<vertexNum;i++){ //k每循環一次,要更新dist和path數組
for(int j=0;j<vertexNum;j++){ if(dist[i][k]+dist[k][j]<dist[i][j]){ dist[i][j]=dist[i][k]+dist[k][j]; //這里兩個path拼接的時候,第一個字符串的最后一個字符和第二個字符串的第一個字符重復 //用substr去除第一個字符串的最后一個字符
string tmp=path[i][k].substr(0,path[i][k].length()-1); path[i][j]=tmp+path[k][j]; } } } } displayDist(); displayPath(); }
完整代碼
#include<iostream>
#define MAX 50
#define INFINIT 65535 #include <string>
using namespace std; class MGraph{ private: int vertexNum,arcNum; //頂點數,邊數
int arc[MAX][MAX]; //鄰接矩陣
string vertex[MAX]; //頂點信息
int dist[MAX][MAX]; string path[MAX][MAX]; public: MGraph(string v[],int n,int e); void display(); void Floyd(); void displayDist(); void displayPath(); }; void MGraph::Floyd(){ for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ dist[i][j]=arc[i][j]; //dist數組初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist為INFINIT則無路徑,dist為0則指向自己
path[i][j]=vertex[i]+vertex[j]; //path數組初始化
else path[i][j]=""; //不符合則path為空串
} } for(int k=0;k<vertexNum;k++){ //k個頂點循環k次
for(int i=0;i<vertexNum;i++){ //k每循環一次,要更新dist和path數組
for(int j=0;j<vertexNum;j++){ if(dist[i][k]+dist[k][j]<dist[i][j]){ dist[i][j]=dist[i][k]+dist[k][j]; //這里兩個path拼接的時候,第一個字符串的最后一個字符和第二個字符串的第一個字符重復 //用substr去除第一個字符串的最后一個字符
string tmp=path[i][k].substr(0,path[i][k].length()-1); path[i][j]=tmp+path[k][j]; } } } } displayDist(); displayPath(); } void MGraph::displayDist(){ //打印dist數組
cout<<"dist數組:"<<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ cout<<dist[i][j]<<"\t"; } cout<<endl; } } void MGraph::displayPath(){ //打印path數組
cout<<"path數組:" <<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ cout<<path[i][j]<<"\t"; } cout<<endl; } } MGraph::MGraph(string v[],int n,int e){ //n是頂點數,e是邊數
vertexNum=n; arcNum=e; for(int i=0;i<vertexNum;i++){ vertex[i]=v[i]; } for(int i=0;i<arcNum;i++){ //初始化鄰接矩陣
for(int j=0;j<arcNum;j++){ if(i==j) arc[i][j]=0; else arc[i][j]=INFINIT; } } int vi,vj,w; for(int i=0;i<arcNum;i++){ cout<<"請輸入有向邊的兩個頂點和這條邊的權值"<<endl; cin>>vi>>vj>>w; //輸入邊依附的兩個頂點的編號 和權值
arc[vi][vj]=w; //有邊標志
} } void MGraph::display(){ cout<<"鄰接矩陣:"<<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ if(arc[i][j]==INFINIT) cout<<"∞"<<"\t"; else cout<<arc[i][j]<<"\t"; } cout<<endl; } cout<<endl; cout<<"結點信息:"<<endl; for(int i=0;i<vertexNum;i++){ cout<<vertex[i]<<" "; } cout<<endl; } int main(){ int n,e; string v[MAX]; cout<<"請輸入頂點數和邊數"<<endl; cin>>n>>e; cout<<"請輸入頂點信息"<<endl; for(int i=0;i<n;i++){ cin>>v[i]; } MGraph mgraph(v,n,e); mgraph.display(); mgraph.Floyd(); return 0; }
輸入:
3 5
a b c
0 1 4
0 2 11
1 0 6
1 2 2
2 0 3
輸出:
鄰接矩陣:
0 4 11
6 0 2
3 ∞ 0
結點信息:
a b c
dist數組:
0 4 6
5 0 2
3 7 0
path數組:
ab abc
bca bc
ca cab
例題:娛樂中心選址
#include<iostream>
#define MAX 50
#define INFINIT 65535 #include <string>
using namespace std; class MGraph{ private: int vertexNum,arcNum; //頂點數,邊數
int arc[MAX][MAX]; //鄰接矩陣
string vertex[MAX]; //頂點信息
int dist[MAX][MAX]; string path[MAX][MAX]; int rowSum[MAX]; int rowMax[MAX]; public: MGraph(string v[],int n,int e); void display(); void Floyd(); void displayDist(); void displayPath(); void bestCentralAmusement(); void displayRowMax(); void displayRowSum(); }; void MGraph::bestCentralAmusement(){ for(int i=0;i<vertexNum;i++) rowSum[i]=0; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ rowSum[i]+=dist[i][j]; } } int tmp; for(int i=0;i<vertexNum;i++){ tmp=0; for(int j=0;j<vertexNum;j++){ if(tmp<dist[i][j]) tmp=dist[i][j]; } rowMax[i]=tmp; } int tmp2=INFINIT; int index=-1; for(int i=0;i<vertexNum;i++){ if(rowMax[i]<tmp2){ tmp2=rowMax[i]; index=i; } if(tmp2==rowMax[i]){ if(rowSum[i]<tmp2){ index=i; }else{ ; } } } displayRowMax(); displayRowSum(); cout<<"index:"<<index<<endl; cout<<"最合適的位置是"<<vertex[index]<<endl; } void MGraph::displayRowSum(){ cout<<"rowSum: "<<endl; for(int i=0;i<vertexNum;i++) cout<<rowSum[i]<<" "; cout<<endl; } void MGraph::displayRowMax(){ cout<<"rowMax:"<<endl; for(int j=0;j<vertexNum;j++) cout<<rowMax[j]<<" "; cout<<endl; } void MGraph::Floyd(){ for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ dist[i][j]=arc[i][j]; //dist數組初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist為INFINIT則無路徑,dist為0則指向自己
path[i][j]=vertex[i]+vertex[j]; //path數組初始化
else path[i][j]=""; //不符合則path為空串
} } for(int k=0;k<vertexNum;k++){ //k個頂點循環k次
for(int i=0;i<vertexNum;i++){ //k每循環一次,要更新dist和path數組
for(int j=0;j<vertexNum;j++){ if(dist[i][k]+dist[k][j]<dist[i][j]){ dist[i][j]=dist[i][k]+dist[k][j]; //這里兩個path拼接的時候,第一個字符串的最后一個字符和第二個字符串的第一個字符重復 //用substr去除第一個字符串的最后一個字符
string tmp=path[i][k].substr(0,path[i][k].length()-1); path[i][j]=tmp+path[k][j]; } } } } displayDist(); displayPath(); } void MGraph::displayDist(){ //打印dist數組
cout<<"dist數組:"<<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ cout<<dist[i][j]<<"\t"; } cout<<endl; } } void MGraph::displayPath(){ //打印path數組
cout<<"path數組:" <<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ cout<<path[i][j]<<"\t"; } cout<<endl; } } MGraph::MGraph(string v[],int n,int e){ //n是頂點數,e是邊數
vertexNum=n; arcNum=e; for(int i=0;i<vertexNum;i++){ vertex[i]=v[i]; } for(int i=0;i<arcNum;i++){ //初始化鄰接矩陣
for(int j=0;j<arcNum;j++){ if(i==j) arc[i][j]=0; else arc[i][j]=INFINIT; } } int vi,vj,w; for(int i=0;i<arcNum;i++){ cout<<"請輸入有向邊的兩個頂點和這條邊的權值"<<endl; cin>>vi>>vj>>w; //輸入邊依附的兩個頂點的編號 和權值
arc[vi][vj]=w; //有邊標志
} } void MGraph::display(){ cout<<"鄰接矩陣:"<<endl; for(int i=0;i<vertexNum;i++){ for(int j=0;j<vertexNum;j++){ if(arc[i][j]==INFINIT) cout<<"∞"<<"\t"; else cout<<arc[i][j]<<"\t"; } cout<<endl; } cout<<endl; cout<<"結點信息:"<<endl; for(int i=0;i<vertexNum;i++){ cout<<vertex[i]<<" "; } cout<<endl; } int main(){ int n,e; string v[MAX]; cout<<"請輸入頂點數和邊數"<<endl; cin>>n>>e; cout<<"請輸入頂點信息"<<endl; for(int i=0;i<n;i++){ cin>>v[i]; } MGraph mgraph(v,n,e); mgraph.display(); mgraph.Floyd(); mgraph.bestCentralAmusement(); return 0; }
輸入:
5 10
a b c d e
0 1 13
0 3 4
1 0 13
1 2 15
1 4 5
2 3 12
3 0 4
3 2 12
4 2 6
4 3 3
輸出:
鄰接矩陣:
0 13 ∞ 4 ∞
13 0 15 ∞ 5
∞ ∞ 0 12 ∞
4 ∞ 12 0 ∞
∞ ∞ 6 3 0
結點信息:
a b c d e
dist數組:
0 13 16 4 18
12 0 11 8 5
16 29 0 12 34
4 17 12 0 22
7 20 6 3 0
path數組:
ab adc ad abe
beda bec bed be
cda cdab cd cdabe
da dab dc dabe
eda edab ec ed
rowMax:
18 12 34 22 20
rowSum:
51 36 91 55 36
index:1
最合適的位置是b