题目传送门:Emergency

题意

给你一个无向图,每个点有一个权值(点权),给定起点和终点,求它们之间的最短路径数量和所有最短路径中的最大点权和。

思路

dijkstra算法求最短路,然后考虑如何计数。
1. 关于求最短路径数量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];
2. 关于求所有最短路径中的最大点权和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
*/