题意:
给出一张无向图,求从起点到终点:(1)最短路的条数,(2)最短路上权值和的最大值,(3)打印最短路上权值和最大的路径
分析:
dis[]:从起点到每个点的最短距离
num[]:从起点到每个点最短路的数量
res[]:从起点到每个点的最短路径上的最大权值和
pre[]:记录起点到每个点的最短路是由那个点更新而来的
(1)更新起点到每个点的最短路时,同时更新数量,更新权值和,更新pre[]
(2)如果最短距离相等,num[v] += num[u],同时权值和取最大值,如果最大权值和更新,同时也要更新pre[]数组
(3)此题m很大,注意每个点只能松弛一次,否则最短路数量要重复算
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+13;
const int inf = 0x3f3f3f3f;
struct edge{
int to,nxt,w;
}e[MAXN<<10];
int head[MAXN],a[MAXN],pre[MAXN],dis[MAXN],num[MAXN],vis[MAXN],res[MAXN],cnt,n,m,s,d,u,v,w;
void add(int u,int v,int w){
e[++cnt].to = v;
e[cnt].nxt = head[u];
e[cnt].w = w;
head[u] = cnt;
}
struct node{
int x,y;
node(int a,int b){x = a;y = b;}
bool friend operator < (node a,node b){
return a.y > b.y;
}
};
void dijkstra(){
priority_queue<node> p;
memset(dis,inf,sizeof(dis));
dis[s] = 0;
num[s] = 1;
pre[s] = -1;
res[s] = a[s];
p.push(node(s,0));
while(!p.empty()){
node now = p.top(); p.pop();
int u = now.x;
if(vis[u]) continue;
vis[u] = 1; //每个点只能松弛一次,否则最短路的数量要重复算
for(int i = head[u]; i ;i = e[i].nxt){
int v = e[i].to;
if(v == u) continue;
if(dis[u] + e[i].w == dis[v]){
num[v] += num[u];
if(res[u] + a[v] > res[v]){
pre[v] = u;
res[v] = res[u] + a[v];
}
}
else if(dis[u] + e[i].w < dis[v]){
pre[v] = u;
res[v] = res[u]+a[v];
num[v] = num[u];
dis[v] = dis[u] + e[i].w;
p.push(node(v,dis[v]));
}
}
}
}
void write(int x){ //递归打印路径
if(pre[x] == -1){
cout<<x;
return ;
}
write(pre[x]);
cout<<" "<<x;
}
int main(){
cin>>n>>m>>s>>d;
for(int i = 0;i < n; ++i) cin>>a[i];
while(m--){
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dijkstra();
cout<<num[d]<<" "<<res[d]<<endl;
write(d);
return 0;
}