题目链接:PTA | 程序设计类实验辅助教学平台
分析:这道题跟其他的dijkstra最短路题目略有不同,这道题目需要求最短路径的方案数,我在这个地方犯了一个错误,卡了挺长时间,一会我会重点说一下这个地方。
因为我们要求最短路径的方案数,所以我们要定义一个f[i]记录到达i节点最短路径的条数,因为还需要统计救援队数量,所以我们还需要定义一个cnt[i]记录到达i节点的最多召集的救援队数量。
接下来我说一下dijkstra更新过程:首先是比较d[j]与d[begin]+w[i](begin与i之间的距离)
如果d[j]>d[begin]+w[i],那么我们此时到达j的最短路径条数就是1,最短路径d[j]=d[begin]+w[i],j的前一个点就是begin,到达j最短路径上的救援队数量最多是cnt[begin]+a[j](a[j]是j点的救援队的数量)
如果d[j]==d[begin]+w[i],这个时候我们应该遵循救援队数量最多的原则,若cnt[j]<cnt[begin]+a[j],则有j点的救援队数量最多为cnt[j]=cnt[begin]+a[j],最短路径长度不变,最短路径的方案数为f[j]=f[j]+f[begin],就是说原来的最短路径方案数加上通过begin到达j的方案数之和,j的前驱节点也就对应地设置为begin。我刚开始以为如果cnt[j]>=cnt[begin]+a[j]时就不用考虑了,后来才发现这样是错误的,原因就是虽然当cnt[j]>=cnt[begin]+a[j]时并不能更新救援队数量,但是能够更新最短路径的方案数。这个地方是我认为比较容易出错的点,也希望大家稍微注意一下这个地方
除了更新过程就没什么了,下面是代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const int N=1003;
int d[N],h[N*N],ne[N*N],e[N*N],w[N*N],idx;
int a[N],cnt[N],pass[N];//cnt[i]记录到达i节点的最多召集的救援队数量
int f[N];//f[i]记录到达i节点最短路径的条数
bool vis[N];
void add(int x,int y,int z)
{
e[idx]=y;
w[idx]=z;
ne[idx]=h[x];
h[x]=idx++;
}
void dijkstra(int x)
{
priority_queue<PII,vector<PII>,greater<PII> >q;
memset(d,0x3f,sizeof d);
d[x]=0;f[x]=1;cnt[x]=a[x];//初始化
memset(vis,false,sizeof vis);
q.push({0,x});
while(!q.empty())
{
int begin=q.top().second;
q.pop();
if(vis[begin]) continue;
vis[begin]=true;
for(int i=h[begin];i!=-1;i=ne[i])
{
int j=e[i];
if(d[j]>d[begin]+w[i])
{
pass[j]=begin;
d[j]=d[begin]+w[i];
f[j]=f[begin];
cnt[j]=cnt[begin]+a[j];
q.push({d[j],j});
}
else if(d[j]==d[begin]+w[i])
{
if(cnt[j]<cnt[begin]+a[j])
{
cnt[j]=cnt[begin]+a[j];
pass[j]=begin;
}
f[j]+=f[begin];//由于这两种路径都是最短路,所以应该把最短路径的方案数相加
q.push({d[j],j});
}
}
}
}
int main()
{
int n,m,S,D;
cin>>n>>m>>S>>D;
S++;D++;//让编号从1开始
for(int i=1;i<=n;i++)
{
h[i]=-1;
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
x++;y++;
add(x,y,z);add(y,x,z);
}
dijkstra(S);
printf("%d %d\n",f[D],cnt[D]);
int st[N],tt=0;
st[++tt]=D;
while(pass[D])
{
st[++tt]=pass[D];
D=pass[D];
}
for(int i=tt;i>=1;i--)
{
printf("%d",st[i]-1);
if(i!=1) printf(" ");
}
return 0;
}