原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
题意求最短路有多少条,其中经过救援队最多的数量是多少。
思路:如何计算最短路有多少条?并且经过的最短路中救援队伍最多?dijkstra是通过已知子集中的元素去找和子集元素最近的一条,并把该点加入子集,然后通过该点到达目的地更近还是直接到达更近。所以我们能做的就是判断这个中间点k和目的地j。第一种情况是dis[j] == dis[k]+e[k][j],这种意味着从k到j和直接到j距离一样,所以最短路数量等于从原点到j加上从原点到k的条数,这里使用tot[maxn]来表示,tot]j]表示目的地为j的最短路条数。第二种情况是dis[j] > dis[k]+e[k][j],表示从k到j比直接到达j更近,所以tot[j]=tot[k],直接把k存在的最短路赋值给j。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#define ll long long
using namespace std;
const int N=505,INF=0x3f3f3f3f;
int a[N],e[N][N];
int vis[N],dis[N],tot[N],num[N]; //tot表示最短路条数,num表示经过的救援队数量
int n,m,c1,c2;
void dijk()
{
for(int i = 0;i < n;++i) dis[i] = e[c1][i];
num[c1] = a[c1];
tot[c1] = 1;
for(int i = 0;i < n;++i)
{
int minor = INF;
int k;
for(int j = 0;j < n;++j)
{
if(!vis[j] && dis[j] < minor)
{
minor = dis[j];
k = j;
}
}
vis[k] = 1;
for(int j = 0;j < n;++j)
{
if(vis[j]) continue;
if(dis[j] == dis[k]+e[k][j])
{
tot[j] += tot[k];
num[j] = max(num[j],num[k]+a[j]);
}
if(dis[j] > dis[k]+e[k][j])
{
dis[j] = dis[k]+e[k][j];
tot[j] = tot[k];
num[j] = num[k]+a[j];
}
}
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&c1,&c2);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
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;
}
}
int s,ed,c;
while(m--){
scanf("%d%d%d",&s,&ed,&c);
e[s][ed]=c;
e[ed][s]=c;
}
dijk();
printf("%d %d\n",tot[c2],num[c2]);
}