作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出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
题意:
输入:第一行给出n,m,s,d, 分别表示城市个数n(城市编号1~(n-1)),道路条数m,始发地编号s,目的地编号d;
第二行分别是n个城市自身包含的救援队数量,接下来m行,每行三个数u,v,w,分别表示编号为u和v的两个城市有路相连,且道路长度为w;
输出:第一行:从s到d的最短路径条数和最多的救援队数量(路径包含的城市的救援队数量之和为该路径的救援队数量,所有路径的救援队数量的max即为所求),第二行:路径(用依次经过的城市编号表示);
思路:
用dijkstra求单源最短路,用pathNum[]数组记录最短路径条数,sum[]数组记录路径包含的最多的救援队数量,并用pre[]数组记录路径即可;
具体内容:用mp[i][j]表示i和j两个城市的道路长度,以此来构建整个图,用num[i]表示i城市的救援队数量,sum[i]表示以i为终点路径的最多救援队数量,pathNum[i]表示以i为终点的最短路径条数,用pre[i]记录最优路径下编号为i的城市的上一个城市的编号,这样最后倒序就能依次找到最优路径从后往前的结点编号了;
先初始化:让vis[]数组初始化为0,让出了i->i的路径的长度都初始化为inf;
跑一遍朴素dijkstra同时不断更新和维护数组信息,最后利用数组记录的信息输出即可。
完整代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1010;
const int inf=0x3f3f3f3f;
int pathNum[maxn],vis[maxn],mp[maxn][maxn],num[maxn],sum[maxn],pre[maxn];
int n,m,s,d;void init(){memset(vis,0,sizeof(vis));for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i!=j){mp[i][j]=mp[j][i]=inf;}}}
}void dijkstra(int s)
{pathNum[s]=vis[s]=1;//先标记起点,以该点出发的最短路径条数初始化为1(因为至少有一条)for(int i=0;i<n-1;i++){//遍历n-1次即可int minlen=inf,k=-1;for(int j=0;j<n;j++){//先找从起点s出发,离起点s最近的一个点kif(!vis[j]&&mp[s][j]<minlen){minlen=mp[s][j];k=j;}}if(k==-1) break;//如果找不到k,说明找完了,则breakvis[k]=1;//实时标记找过的点for(int j=0;j<n;j++){//这次循环再找以k为中转点更得到的更短的路径if(!vis[j]&&mp[s][k]+mp[k][j]<mp[s][j]){mp[s][j]=mp[s][k]+mp[k][j];pre[j]=k;pathNum[j]=pathNum[k];sum[j]=sum[k]+num[j];}else if(!vis[j]&&mp[s][k]+mp[k][j]==mp[s][j]){pathNum[j]+=pathNum[k];//新的路径长度和原来最短路径长度相等,说明都是最短路,这时当前记录的最短路条数就要加上原来记录的这个长度的最短路条数if(sum[k]+num[j]>sum[j]){//只有新的最短路的救援队数量比之前多时,才把路径信息更新成当前新的最短路的路径信息pre[j]=k;sum[j]=sum[k]+num[j];}}}}
}signed main()
{ios::sync_with_stdio(false);cin.tie(0);cin>>n>>m>>s>>d;init();for(int i=0;i<n;i++){cin>>num[i];sum[i]=num[i];//最初i号城市的最多救援队数量即为其自身包含的数量pathNum[i]=1;//以每个城市为终点的最短路径条数至少为1条,所以出初始化为1}while(m--){int u,v,w;cin>>u>>v>>w;mp[u][v]=mp[v][u]=w;}dijkstra(s);cout<<pathNum[d]<<" "<<sum[d]+num[s]<<endl;//注意这里数量要再加上起点自身的数量(因为该数组没记录起点信息)int path[maxn],cnt=0,p=d;while(pre[p]){//循环倒序记录路径每个点的编号path[cnt++]=pre[p];p=pre[p];}cout<<s;for(int i=cnt-1;i>=0;i--){cout<<" "<<path[i];}cout<<" "<<d<<endl;return 0;
}