题目传送门:Emergency
题意
给你一个无向图,每个点有一个权值(点权),给定起点和终点,求它们之间的最短路径数量和所有最短路径中的最大点权和。
思路
dijkstra算法求最短路,然后考虑如何计数。
- 关于求最短路径数量path[i]。设起点为s,当前点为u,连接的下一个点为v,在更新最短路的过程中:
a) s到u最短距离+u到v距离 < s到v最短距离,则path[v]=path[u];
b) s到u最短距离+u到v距离 = s到v最短距离,则path[v]+=path[u]; - 关于求所有最短路径中的最大点权和sumval[i]。
若s到u最短距离+u到v距离 <= s到v最短距离,则更新最小点权和:sumval[v]=max(sumval[v],sumval[u]+val[v]);
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=510,inf=0x7f7f7f7f;
int n,m,s,t,cnt,dis[N],val[N],head[N]; // s到i最短距离为dis[i];点权val[i]
int path[N],sumval[N];
bool vis[N];
struct edge
{
int to,w,next;
}e[N*N];
void add(int x,int y,int z)
{
e[cnt].to=y;
e[cnt].w=z;
e[cnt].next=head[x];
head[x]=cnt++;
}
void add_edge(int x,int y,int z)
{
add(x,y,z);
add(y,x,z);
}
struct node
{
int u,w; // w是距离
bool operator < (const node &s) const
{
return w>s.w;
}
};
void dijkstra()
{
priority_queue<node>q;
memset(dis,inf,sizeof(dis));
dis[s]=0;
path[s]=1;
sumval[s]=val[s];
q.push({s,0});
while(q.size())
{
int u=q.top().u;q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
// 更新最短路径数
if(dis[u]+w<dis[v])
{
path[v]=path[u];
dis[v]=dis[u]+w;
q.push({v,dis[v]});
}
else if(dis[u]+w==dis[v])
{
path[v]+=path[u];
}
// 更新最小点权和
if(dis[u]+w<=dis[v])
sumval[v]=max(sumval[v],sumval[u]+val[v]);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>s>>t;
memset(head,-1,sizeof(head));
for(int i=0;i<n;i++)
cin>>val[i];
int x,y,z;
for(int i=0;i<m;i++)
{
cin>>x>>y>>z;
add_edge(x,y,z);
}
dijkstra();
printf("%d %d\n",path[t],sumval[t]);
return 0;
}
/*
5 6 0 4
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 2
ans:3 9
*/