PTAL2-001 紧急救援(Dijkstra)
Description
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
Input
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
Output
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
Sample Input
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
Sample Output
2 60
0 1 3
题意
迪杰斯特拉模板题,需要记录最短路径的条数和最短路径上最多能召集多少救援队,以及输出能召集最多救援队的最短路径。
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
#include<functional>
#include<map>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N=1e5+10,NN=1e3+10,INF=0x3f3f3f3f;
const ll MOD=1e9+7;
struct Edge{
int from;
int to;
int dis;
Edge(int u,int v,int w):from(u),to(v),dis(w){}//分别为起点,终点,权值
};
struct Node{
int id;//结点
int dis;//这个结点到起点的距离
int sum;//这个结点到起点能召集多少救援队
Node(int v,int w,int sum):id(v),dis(w),sum(sum){}
bool friend operator<(const Node &a,const Node &b){//根据题意排序
if(a.dis==b.dis) return a.sum<b.sum;
return a.dis>b.dis;
}
};
vector<Edge>e[NN];//邻接表存图
int n,m,head,tail;//head是起点,tail是终点
int city[N];//每个城市有多少个救援队
int pre[NN];//记录路径前驱的数组
void print_path(int s,int t){//打印s到t的最短距离
if(s==t){
printf("%d",s);
return ;
}
print_path(s,pre[t]);
printf(" %d",t);
}
void dijkstra(){
int s=head;//起点
int dis[NN];//计算所有结点到起点的距离
int sum[NN];//计算这个结点到起点召集了多少救援队
int cnt[NN];//计算到这个结点的路径数量
bool done[NN];//值为true表示到结点i的最短路径已经找到
for(int i=0;i<n;i++){//初始化
dis[i]=INF;
sum[i]=-INF;
done[i]=false;
}
dis[s]=0;//表示起点到自己的距离是0
sum[s]=city[s];//起点本身就有一定数量的救援队
cnt[s]=1;
priority_queue<Node>q;
q.push(Node(s,dis[s],sum[s]));
while(!q.empty()){
Node u=q.top();
q.pop();//pop出距离起点最近的结点u
if(done[u.id]) continue;//若该结点已经找到最短路径,则跳过
done[u.id]=true;
for(int i=0;i<e[u.id].size();i++){//检查结点的所有邻居
Edge v=e[u.id][i];
if(done[v.to]) continue;
if(dis[v.to]>v.dis+u.dis){
dis[v.to]=v.dis+u.dis;
sum[v.to]=sum[u.id]+city[v.to];
cnt[v.to]=cnt[u.id];
q.push(Node(v.to,dis[v.to],sum[v.to]));//拓展新邻居,放入优先队列
pre[v.to]=u.id;//记录路径
}
else if(dis[v.to]==v.dis+u.dis){
cnt[v.to]+=cnt[u.id];
if(sum[v.to]<sum[u.id]+city[v.to]){
sum[v.to]=sum[u.id]+city[v.to];
q.push(Node(v.to,dis[v.to],sum[v.to]));
pre[v.to]=u.id;
}
}
}
}
printf("%d %d\n",cnt[tail],sum[tail]);
print_path(head,tail);//若有需要则打印路径
puts("");
}
void init(){
}
int main(){
scanf("%d%d%d%d",&n,&m,&head,&tail);
for(int i=0;i<n;i++){
int num;
scanf("%d",&num);
city[i]=num;
}
for(int i=0;i<n;i++) e[i].clear();
while(m--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u].push_back(Edge(u,v,w));
e[v].push_back(Edge(v,u,w));
}
dijkstra();
}