L2-001 紧急救援 (25 分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出 \(4\) 个正整数 \(N\)、\(M\)、\(S\)、\(D\),其中 \(N \; (2 \leq N \leq 500)\) 是城市的个数,顺便假设城市的编号为 \(0 \sim (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
输出样例1:
2 60
0 1 3
解题思路:
求单源最短路径,可使用堆优化的 \(Dijkstra\) 算法(非负权图不推荐使用 \(Spfa\)),可以用优先队列代替堆,递归法打印路径。
有关 \(Dijkstra\) 算法,可参考 Dijkstra + 堆优化;
有关 \(Spfa\) 算法,可参考 Spfa 以及 Spfa + SLF&LLL优化。
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 505
#define maxm 250005
#define INF 1234567890
int n,m,k,s,d,c[maxn],cnt,head[maxn],vis[maxn],dis[maxn],cis[maxn],a[maxn],pre[maxn];
struct Edge{int u,v,w,next;}edge[maxm];
struct node
{
int w,t,now;
inline bool operator<(const node &x)const
{
if(w==x.w)return t<x.t;
return w>x.w;
}
};
priority_queue<node>q;
inline void add(int u,int v,int w)
{
edge[++cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
inline void printPath(int x)
{
if(x==s){cout<<x;return;}
printPath(pre[x]);
cout<<' '<<x;
}
inline void Dijkstra()
{
for(int i=0;i<=n;i++)
{
dis[i]=INF;
vis[i]=0;
}
dis[s]=0;
a[s]=1;
cis[s]=c[s];
q.push((node){0,cis[s],s});
while(!q.empty())
{
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].v;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
a[v]=a[u];
pre[v]=u;
cis[v]=cis[u]+c[v];
q.push((node){dis[v],cis[v],v});
}
else if(dis[v]==dis[u]+edge[i].w)
{
a[v]+=a[u];
if(cis[v]<cis[u]+c[v])
{
cis[v]=cis[u]+c[v];
pre[v]=u;
q.push((node){dis[v],cis[v],v});
}
}
}
}
}
int main()
{
cin>>n>>m>>s>>d;
for(int i=0;i<n;i++)cin>>c[i];
int u,v,w;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
Dijkstra();
cout<<a[d]<<' '<<cis[d]<<endl;
printPath(d);
return 0;
}