题目详情 - 1003 Emergency (pintia.cn)
题目解释:
n个城市之间存在m条路径,每条路径有相应的距离,每个城市有一定数量的救援队,请你找出给出的某两个城市之间的最短路径的数量,并找到这些最短路径中救援队数量的最大值。
思路分析:
很明显这是一个典型的单源汇没有负权求最短路的问题,可以使用dijkstra算法,但是要注意比一般的dijkstra算法多了求最短路径的条数和考虑点权的问题,只需要在更新最短路的过程中增加相应的操作即可,当d[j]>distance+w[i]时需要更新最短距离,最短路数量不变,点权和需要更新;当d[j]==distance+w[i]时最短路数量更新为num[j]=num[x]+num[j],同时点权和更新为最短路中的最大值。
#include<iostream>
using namespace std;
#include<algorithm>
#include<queue>
#include<cstring>
typedef pair<int,int>pii;
const int N=510,M=2*N;
int h[N],e[M],ne[M],w[M],v[N],idx=0,d[N],num[N],amount[N];
//h存储邻接表每个节点的头结点,e存储结点的值,ne存储下一个节点的标号
//idx为边的标号,w存储边的权值,v存储每个点的点权,d存储每个节点到起点的最短距离
//num存储每个点到起点最短路的条数,amount存储这些最短路中点权和的最大值
int n,m,c1,c2;
bool st[N];//表示该点是否确定最短路
priority_queue<pii,vector<pii>,greater<pii>>heap;
void add(int x,int y,int z){//建边
e[idx]=y;
w[idx]=z;
ne[idx]=h[x];
h[x]=idx++;
}
void dijkstra(){
d[c1]=0;
num[c1]=1;
amount[c1]=v[c1];//初始化
heap.push({0,c1});
while(heap.size()){//堆优化的dijkstra算法
pii t=heap.top();
heap.pop();
int distance=t.first,x=t.second;
if(st[x]) continue;
st[x]=true;
for(int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
if(d[j]>distance+w[i]){
d[j]=distance+w[i];//更新最短距离
num[j]=num[x];//最短路的数量不变
amount[j]=amount[x]+v[j];//路径上点变化,点权也跟着更新
heap.push({d[j],j});
}else if(d[j]==distance+w[i]){
num[j]=num[x]+num[j];//最短路数量更新
amount[j]=max(amount[j],amount[x]+v[j]);//点权和更新为所有最短路中点权和的最大值
}
}
}
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&c1,&c2);
memset(h,-1,sizeof h);
memset(d,0x3f,sizeof d);
for(int i=0;i<n;i++) scanf("%d",&v[i]);
for(int i=0;i<m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);//无向图
}
dijkstra();
printf("%d %d\n",num[c2],amount[c2]);
return 0;
}