题目连接
https://pta.patest.cn/pta/test/15/exam/4/question/862
5-35 城市间紧急救援 (25分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数NN、MM、SS、DD,其中NN(2\le N\le 5002≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N-1)(N−1);MM是快速道路的条数;SS是出发地的城市编号;DD是目的地的城市编号。
第二行给出NN个正整数,其中第ii个数是第ii个城市的救援队的数目,数字间以空格分隔。随后的MM行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从SS到DD的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
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
分析:
这个问题首先是一个最短路的算法,这个载体还是比较简单的,但是,它的难点就在于它的相关附加内容。
路径就用一个path数组记录,然后用一个递归调用就可以了。
救援队的数量也是用一个数组来存放。
这个问题的关键是最短路径的条数,这个问题我先是用一个全局变量来存放,可是后来发现这样不行,因为可能有几种不同的到达方式。
所以就用了一个数组,又前往后的推理分析,从而得出最后的结论。
但这道题确实好,坑也确实挺多,首先就是if else的分析,我以前不太喜欢用else这次就被坑惨了。。
还有就是这个题,为了防止一些不必要的访问,对我原有的问题进行干扰,我设置了两个标记数组。vis主要是为了最短路而设计的,而另一个visited数组,主要是为了防止有一样的距离时,对我原有的好的结果造成干扰。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define infinity 100000
int arc[520][520]; // array for the picture
int dist[520]; //distance from the start city
int emer[520]; // emergency team at every city
int vis[520]; // mark array
int visited[520]; // another mark array
int path[520];
int rever_path[520];
int total_team[520]; // this node 's emergency team
int ans[520];
int main()
{
memset(ans,0,sizeof(ans));
int n,m,s,d; // n:the num of the city ; m:the num of the road; s:start city ; d:destination city;
//freopen("1.txt","r+",stdin);
scanf("%d%d%d%d",&n,&m,&s,&d);
for(int i=0; i<n; i++)
scanf("%d",&emer[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
arc[i][j]=arc[j][i]=infinity;
}
for(int i=0; i<m; i++)
{
int start,next,distance;
scanf("%d%d%d",&start,&next,&distance);
arc[start][next]=arc[next][start]=distance;
}
if(s==d)
{
printf("1 %d\n",emer[s]);
printf("%d\n",s);
}
else{
for(int i=0; i<n; i++)
{
dist[i]=infinity;
if(arc[s][i]!=infinity)
{
dist[i]=arc[s][i];
ans[i]++;
}
}
for(int i=0; i<n; i++)
total_team[i]=emer[s];
memset(vis,0,sizeof(vis));
memset(visited,0,sizeof(visited));
dist[s]=0;
vis[s]=1;
int total_mindist=1;
for(int j=1; j<n; j++)
{
//printf("%d@\n",ans[3]);
int min_distance=infinity,min_position=s;
for(int i=0; i<n; i++)
{
if(!vis[i])
if(dist[i]<min_distance)
{
min_distance=dist[i];
min_position=i;
}
}
//ans[min_position]++;
vis[min_position]=1;
if(!visited[min_position]){
path[min_position]=s;
total_team[min_position]+=emer[min_position];
}
// printf("%d\n",min_position);
for(int i=0; i<n; i++)
{
if(!vis[i])
{
if(min_distance+arc[min_position][i]<dist[i])
{
ans[i]=ans[min_position];
//printf("%d11\n",ans[3]);
total_mindist=1;
dist[i]=min_distance+arc[min_position][i];
path[i]=min_position;
total_team[i]=total_team[min_position]+emer[i];
//printf("%d!*\n",total_team[3]);
visited[i]=1;
}
else if(min_distance+arc[min_position][i]==dist[i]) // else 防止上一个if语句对这个if造成的影响
{
ans[i]+=ans[min_position]; // 原来的路径数加上新增的路径数
if(total_team[min_position]+emer[i]>total_team[i])
{
total_mindist++;
total_team[i]=total_team[min_position]+emer[i];
path[i]=min_position;
//printf("%d\n",path[i]);
//printf("%d!\n",total_team[3]);
visited[i]=1;
}
}
}
// printf("%d!0%d\n",total_team[3],ans[3]);
}
}
int num=d,path_num=0;
//printf("%d0\n",path[3]);
while(num!=s)
{
//printf("%d\n",num);
//printf("#%d\n",path[num]);
rever_path[path_num]=num;
path_num++;
num=path[num];
//printf("%d\n",num);
}
rever_path[path_num]=s;
printf("%d %d\n",ans[d],total_team[d]);
num=d;
for(int i=path_num; i>0; i--)
printf("%d ",rever_path[i]);
printf("%d\n",d);
}
return 0;
}