【問題描述】
給定n個村庄之間的交通圖,若村庄i和j之間有道路,則將頂點i和j用邊連接,邊上的Wij表示這條道路的長度,現在要從這n個村庄中選擇一個村庄建一所醫院。
【基本要求】
這所醫院應建在哪個村庄,才能使離醫院最遠的村庄到醫院的路程最短?試設計一個解答上述問題的算法,並應用該算法解答如圖所示的實例。
【提示】
最短路徑的應用
#include<iostream> #define INFINITY 10000//最大數 using namespace std; const int maxEdges=50; const int maxVertices=100; //最大頂點數 struct PathWay{ double dist;//權值 }; class MyGraph { private: int vNum;//當前頂點數 int eNum;//當前邊數 char Vertex[maxVertices];//頂點數組 PathWay Edge[maxVertices][maxVertices];//邊數組 public: void Create(int size = maxEdges);//構造函數 bool FindVertex(int vertex); bool InsertVertex(int vertex);//插入一個頂點vertex bool InsertEdge(const int v1,const int v2,const int weight);//插入一條邊(v1,v2),該邊上的權值為weight bool GetVertexPos(const int &vertex,int &i);//給出頂點vertex在圖中的位置 void Floyd();//Floyd算法 void Print();//輸出鄰接矩陣 void short_compare(double farthest[]);//求出最短路徑 double far_compare(double shortest[]);//這個問題的答案,在short_compare函數中選出一個最小的值 }; void MyGraph::Create(int size)//將圖轉化成鄰接矩陣保存 { int n,e;//n是村庄數,e是邊數 char name,tail,head; int weight; for(int i=0;i<size;i++){ for(int j=0;j<size;j++) { if(i==j){ Edge[i][j].dist=0;//初始化頂點到自身權值為0 } else{ Edge[i][j].dist=INFINITY;//初始化鄰接矩陣其余頂點為最大值 } } } cout<<"請輸入總頂點數(村庄):"; cin>>n; while(cin.fail()){ cin.clear(); char temp[100]; cin.getline(temp,100); cout<<endl; cout<<"Error:您輸入的不是數字."<<endl<<"請重新輸入:"; cin>>n; cout<<endl; } cout<<"請輸入總邊數(路徑):"; cin>>e; while(cin.fail()){ cin.clear(); char temp[100]; cin.getline(temp,100); cout<<endl; cout<<"Error:您輸入的不是數字."<<endl<<"請重新輸入:"; cin>>e; cout<<endl; } cout<<endl; cout<<"請輸入頂點名稱:"<<endl; for(int i=0;i<n;i++)//依次輸入頂點,插入圖中 { cout<<"請輸入第"<<i+1<<"個頂點(村庄)的名稱:"; cin>>name; InsertVertex(name); vNum++; } cout<<endl; cout<<"請輸入頭尾兩個頂點(村庄)和權值(路徑)[分別用空格隔開]:"<<endl; for(int i=0;i<e;i++){ cin>>head>>tail>>weight; if(!InsertEdge(head,tail,weight)) { cout<<"不存在該邊,請重新輸入這條邊:"; i--; continue; } } cout<<endl; } void MyGraph::short_compare(double farthest[]){ //比較數組(當前村庄和其他村庄間最短距離的集合中最大值的集合)中的最小值。選擇使離醫院最遠的村庄到醫院的路程最短 double route=farthest[0]; int point=0; for (int i=0; i<vNum; i++) { if (farthest[i]<route) { route=farthest[i]; point=i; } } cout<<"所以醫院應該建在村庄:"<<Vertex[point]<<endl; } double MyGraph::far_compare(double s[]){//得到最遠村庄的距離 double max=s[0]; int k; for(k=0;k<vNum;k++){ if(s[k]>max){ max=s[k]; } } return max; } bool MyGraph::FindVertex(int vertex)//給出頂點vertex在圖中的位置,這里也可以用來判斷在插入的時候是否已經有頂點了 { for (int i = 0; i < vNum; i++){ if (vertex == Vertex[i]){ return true; } } return false; } bool MyGraph::InsertVertex(int vertex)//插入頂點 { if (FindVertex(vertex)){ return false; } else{ Vertex[vNum] = vertex; return true; } } bool MyGraph::GetVertexPos(const int& vertex,int &i)//這個點是否在這條邊上 { for (i = 0; i < vNum; i++){ if (vertex == Vertex[i]){ return true; } } return false; } bool MyGraph::InsertEdge(int v1,int v2,int weight)//插入一條邊 { int k=0,j=0; if(GetVertexPos(v1,k) && GetVertexPos(v2,j)) { Edge[k][j].dist=weight; eNum++; Edge[j][k].dist=weight; eNum++; return true; } else{ return false; } } void MyGraph::Floyd() { double map[maxVertices][maxVertices],shortDistance[maxVertices],longDistance[maxVertices];//longDistance就是我們問題的答案 //map存放其他村庄到當前村庄的路徑和,shortDistance當前村庄到最遠村庄的最短距離,longDistance是shortDistance中的最大距離 int current,start,mid,i,j,k; j=k=0; for (current=0; current<vNum; current++){ for (start=0; start<vNum; start++) { map[current][start] = Edge[current][start].dist; } }//各對結點之間初始已知路徑及距離 for (mid=0; mid<vNum; mid++){ if(vNum-1 == mid){ //這里看插入的點是否等於頂點數減一,如果小於的話證明還沒插完整,加上前面的繼續插,不可能大於,然后插到倒數第一個,比方說 //我們這個題有6個點,則插五個點就夠了,排除自己的。然后當插到第五個點的時候我們就可以判斷第五個點插進去是否小於之前的,然后輸出他的距離。 for(current=0; current<vNum; current++){ k=0; shortDistance[k]=0; for (start=0; start<vNum; start++){ if (map[current][mid] + map[mid][start] < map[current][start]){ map[current][start] = map[current][mid] + map[mid][start]; } if(current != start){//這里要杜絕自己到自己的路徑 cout<<"村庄"<<Vertex[current]<<"到村庄"<<Vertex[start]<<"的最短距離為:"<<map[current][start]<<endl; shortDistance[k] = map[current][start]; k++; } } longDistance[j] = far_compare(shortDistance); cout<<"村庄"<<Vertex[current]<<"到最遠的村庄的最短距離為:"<<longDistance[j]<<endl; j++; cout<<endl; } }else{//沒有插完整的話繼續插 for (current=0; current<vNum; current++){ for (start=0; start<vNum; start++){ if (map[current][mid] + map[mid][start] < map[current][start]){ map[current][start] = map[current][mid] + map[mid][start]; } } } } } short_compare(longDistance); } void MyGraph::Print(){ int i,j,count=0; cout<<"所得圖的鄰接矩陣為:"<<endl; for(i=0;i<vNum;i++){ for(j=0;j<vNum;j++){ if(Edge[i][j].dist!=INFINITY){ cout<<Edge[i][j].dist<<"\t"; } else if(i==j){ cout<<0<<"\t"; } else{ cout<<"∞"<<"\t"; } count++; } if(count%vNum==0){ cout<<endl; } } cout<<endl; } int main() { MyGraph Hospital; Hospital.Create(maxVertices); Hospital.Print(); Hospital.Floyd(); return 0; }