题目描述
As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.
输入描述
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1 and C 2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.
输出描述
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C
2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.
样例
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1
2 4
思路
简单读了一下题,发现这题实际上是个裸的
单源最短路计数+最大点权和
虽然数据范围很小,暴搜应该也能过,但为了复健图论还是老老实实写了Dijkstra,邻接表存图在处理点的时候似乎容易一些,但 我 已 经 不 会 了 !
果断选择链式前向星存图,然后由于题目要求计数+最大点权和,所以在跑Dijkstra的时候根据不同情况进行维护.
初始化
r[c1].t=1;
先把c1节点自己的最短路数赋值为1,因为自己到自己算一条路,同时也能继续更新其他节点的路数.
对于路数和点权和的维护
if(dis[u]+w==dis[v]){
r[v].t+=r[u].t;
r[v].rs=max(r[v].rs,r[u].rs+r[v].r);
}
这是一次二选一,路数直接加,但点权和要取较大的.
if(dis[u]+w<dis[v]){
r[v].t=r[u].t;
r[v].rs=r[u].rs+r[v].r;
}
这是一次一进一,路数直接覆盖,点权和直接加.
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int inf=1e9+7;//极大值
int head[100010],cnt,m,n,dis[505],c1,c2;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}//读入优化!
struct edge{
int to,w,next;
}e[500005];//链式前向星
struct wtf{//好变量名233
int t,r,rs;
}r[505];
void add(int u,int v,int w){
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}//加边
struct node{
int u,d;
friend bool operator<(const node &a,const node &b){
return a.d>b.d;
}
};
void Dijkstra(){
for(int i=0;i<n;i++) dis[i]=inf;
dis[c1]=0;
priority_queue<node>q;
node x;
x.u=c1,x.d=0;
q.push(x);
while(!q.empty()){
node fr=q.top();
q.pop();
int u=fr.u,d=fr.d;
if(d!=dis[u]) continue;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(dis[u]+w==dis[v]){
r[v].t+=r[u].t;
r[v].rs=max(r[v].rs,r[u].rs+r[v].r);//更新路和点权和
}
if(dis[u]+w<dis[v]){
r[v].t=r[u].t;//更新路
r[v].rs=r[u].rs+r[v].r;//更新点权和
dis[v]=dis[u]+w;
node y;
y.u=v,y.d=dis[v];
q.push(y);
}
}
}
}
int main(){
n=read(),m=read(),c1=read(),c2=read();
for(int i=0;i<n;i++) r[i].rs = r[i].r=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
}
r[c1].t=1;
Dijkstra();
cout<<r[c2].t<<" "<<r[c2].rs<<endl;
return 0;
}
丢人
因为没存双向边所以一直WA两个点,吐槽数据水的同时…下次一定要好好读题啊!!!
本文深入解析Dijkstra算法在解决单源最短路径问题中的应用,特别是在处理城市间救援团队快速调度场景时,如何通过计数最短路径和最大化点权和来优化救援效率。
387

被折叠的 条评论
为什么被折叠?



