最短路徑(Floyd演算法)

gonghr發表於2021-04-04

宣告:圖片及內容基於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

 

相關文章