7-1 城市間緊急救援 (25 分)
做爲一個城市的應急救援隊伍的負責人,你有一張特殊的全國地圖。在地圖上顯示有多個分散的城市和一些鏈接城市的快速道路。每一個城市的救援隊數量和每一條鏈接兩個城市的快速道路長度都標在地圖上。當其餘城市有緊急求助電話給你的時候,你的任務是帶領你的救援隊儘快趕往事發地,同時,一路上召集儘量多的救援隊。ios
輸入格式:
輸入第一行給出4個正整數N、M、S、D,其中N(2≤N≤500)是城市的個數,順便假設城市的編號爲0 ~ (N−1);M是快速道路的條數;S是出發地的城市編號;D是目的地的城市編號。算法
第二行給出N個正整數,其中第i個數是第i個城市的救援隊的數目,數字間以空格分隔。隨後的M行中,每行給出一條快速道路的信息,分別是:城市一、城市二、快速道路的長度,中間用空格分開,數字均爲整數且不超過500。輸入保證救援可行且最優解惟一。數組
輸出格式:
第一行輸出最短路徑的條數和可以召集的最多的救援隊數量。第二行輸出從S到D的路徑中通過的城市編號。數字間以空格分隔,輸出結尾不能有多餘空格。測試
輸入樣例:
4 5 0 3 20 30 40 10 0 1 1 1 3 2 0 3 3 0 2 2 2 3 2
輸出樣例:
2 60 0 1 3
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 struct 5 { 6 int visit;//該城市是否已做爲最近點被訪問 7 int minlen;//該城市到救援城市的距離 8 int man;//在該城市已經集合的救援隊人數 9 int cont;//到該城市有幾條同長度最短路徑 10 int pre;//到該城市的前一個前一個城市序號 11 }Visit[521]; 12 int Graph[521][521];//城市地圖 13 int cityman[521];//每一個城市的救援隊數量 14 void InitVisit(int N, int S, int D)//初始化Visit 15 { 16 for(int i=0; i<N; i++){ 17 Visit[i].minlen = 521;//將每一個城市的最短路徑都設爲最大,521 18 Visit[i].visit = 0;//都設爲未訪問 19 Visit[i].cont = 1;//最短路徑數量都設爲1 20 Visit[i].man = 0;//將救援隊數量都初始化爲0 21 } 22 //Visit[S].man = cityman[S]; 23 Visit[S].visit = 1; 24 } 25 void InitGraph(int N, int M)//初始化城市地圖 26 { 27 for(int i=0; i<=N; i++) 28 for(int j=0; j<=N; j++) 29 Graph[i][j] = 521;//初始化任意兩個城市間的距離爲521 30 int v1, v2, s; 31 for(int i=0; i<M; i++){//輸入城市地圖 32 cin>>v1>>v2>>s; 33 Graph[v1][v2] = s; 34 Graph[v2][v1] = s; 35 } 36 } 37 int DKS_GetMi(int N, int S, int D)//根據迪傑斯特拉算法求單源點最短路徑 38 { 39 for(int i=0; i<=N; i++){//根據城市地圖更新Visit 40 Visit[i].minlen=Graph[i][S]; 41 if(Graph[i][S]!=521){ 42 Visit[i].man = cityman[i]+cityman[S]; 43 Visit[i].pre = S;//若是到源城市有路徑,則設該城市的前一個城市爲源城市 44 } 45 } 46 47 for(int j=1; j<N; j++){//循環N-1次,每次找到剩餘城市中距離最近的 48 int minpoint = N;//第N個點已設置爲無窮遠 49 for(int i=0; i<N; i++){//找到未訪問的最近的城市 50 if(Visit[i].minlen<Visit[minpoint].minlen&&!Visit[i].visit) 51 minpoint = i; 52 } 53 Visit[minpoint].visit=1;//將找到的最近的城市設置爲已訪問 54 for(int i=0; i<N; i++){//根據找到的最近點的城市更新其餘城市的距離 55 if(!Visit[i].visit){ 56 if(Visit[i].minlen>Visit[minpoint].minlen+Graph[i][minpoint]){//如有更短距離則更新 57 Visit[i].minlen = Visit[minpoint].minlen+Graph[i][minpoint];//更新最短距離 58 Visit[i].man = Visit[minpoint].man+cityman[i];//修改彙集的救援隊人數:上一個城市集合的數量加上分配在該城市的數量 59 Visit[i].pre = minpoint;//設置上一個城市的序號 60 Visit[i].cont = Visit[minpoint].cont;//更新同長度路徑數量:爲上一個城市的同長度路徑數量 61 } 62 else if(Visit[i].minlen==Visit[minpoint].minlen+Graph[i][minpoint]){//若路徑相等,則更新有關信息 63 Visit[i].cont += Visit[minpoint].cont;//相等路徑數量爲:原來的數量 + 新路徑中到前一個城市的相等路徑數量 64 if(Visit[i].man<cityman[i]+Visit[minpoint].man){//選擇能集合救援隊最多的 65 Visit[i].man = cityman[i]+Visit[minpoint].man; 66 Visit[i].pre = minpoint; 67 } 68 } 69 } 70 } 71 } 72 73 } 74 int main() 75 { 76 int N, M, S, D; 77 cin>>N>>M>>S>>D; 78 for(int i=0; i<N; i++){ 79 cin>>cityman[i]; 80 } 81 InitVisit(N, S, D); 82 InitGraph(N,M); 83 DKS_GetMi(N,S,D); 84 cout<<Visit[D].cont<<" "<<Visit[D].man<<endl; 85 // 創建數組存儲路徑序列 86 int a[521]; 87 int len = 520; 88 int pre = D; 89 while(pre!=S){//從目的地找前一個城市,一直找到源城市 90 a[len] = pre; 91 pre = Visit[pre].pre; 92 len--; 93 } 94 a[len] = S; 95 for(int i=len; i<521; i++){ 96 if(i==len) 97 cout<<a[i]; 98 else 99 cout<<" "<<a[i]; 100 } 101 102 } 103 /*新增測試數據 104 5 6 0 4 105 20 30 40 10 20 106 0 1 1 107 0 2 1 108 0 3 1 109 1 4 2 110 2 4 2 111 3 4 2 112 */