7-1 城市间紧急救援 (25 分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过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 */