PAT - L2-001. 紧急救援( Dijstra )

时间:2023-03-09 22:47:27
PAT - L2-001. 紧急救援( Dijstra )

    -

PAT - L2-001. 紧急救援

题目链接

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出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

**

题解:这是一道求最短路径的题,这种类型的是我第一次做,开始的时候用的是Dijstra求出最短路径,然后用最短路径的值,和所到达d值,在再进行了一次DFS求最短路径的最大救援数,及其路线,最后样例过了,提交错了,改了好久找不到错。然后百度了一下看了这道题的题解。思路是Dijstra求最短路径的条数 + 一个其他条件的处理(满足最短路径的情况下求最大救援数)。

#include <bits/stdc++.h>
#define inf 99999999
using namespace std; int n, m, s, d, x, y, z;
int a[505], e[505][505], vis[505], dis[505], pre[505], sum[505], count1[505], z1[505]; void init(){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i==j)e[i][j]=0;
else e[i][j]=inf; for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<m;i++){
cin>>x>>y>>z;
e[x][y] = e[y][x] = z;
}
} void Dijstra(int v0){
for(int i=0;i<n;i++) dis[i]=inf;
memset(vis,0,sizeof(vis));
memset(count1,0,sizeof(count1));
memset(sum,0,sizeof(sum));
vis[v0] = 1;
count1[v0] = 1;
sum[v0] = a[v0]; for(int i=0;i<n;i++){
dis[i] = e[v0][i];
//此部分为扩展部分 根据优先级应该是路径(一) 然后救援人数(二) 其中还要记录当前路径个数
if( e[v0][i] != inf && i != v0 ){
pre[i] = v0; //用来记录经过i结点必须要经过的上一个结点
sum[i] = a[v0] + a[i]; //用来求从v0到当前结点走过的最长救援人数
count1[i] = 1; //用来记录到达当前路径的个数。
}
}
for(int j=0;j<n;j++){
int min = inf, v = v0;
//Dijstra第一步找出最短路径
for(int i=0;i<n;i++){
if(vis[i]==0 && dis[i]<min){
min = dis[i]; v = i;
}
}
vis[v] = 1;
// 开始更新各个的值
for(int i=0;i<n;i++){
if(vis[i]==0) {
if( dis[i] > dis[v] + e[v][i]) {
dis[i] = dis[v] + e[v][i];//优先级最高的路径先更新
pre[i] = v;
sum[i] = a[i] + sum[v];
count1[i] = count1[v];//路线变为上一个点的路线
}
else if(dis[i] == dis[v]+e[v][i]){
//如果相等的话优先级低的也要更新,且附加的值也会改变
count1[i] = count1[i] + count1[v];
//判断优先级底的是否更新
if( sum[i] < a[i] + sum[v] ){
sum[i] = a[i] + sum[v];
pre[i] = v;
}
}
}
}
}
} int main(){
cin>>n>>m>>s>>d;
init();
Dijstra(s);
cout<<count1[d]<<" "<<sum[d]<<endl;
int i = 0, cur = d;
while(cur!=s){
z1[i++] = cur;
cur = pre[cur];
}
z1[i] = s;
for(;i>0;i--)
cout<<z1[i]<<" ";
cout<<z1[0];
}