题目大意:
给定 n m s t ;表示n个点编号为0~n-1 m条边 起点s终点t
接下来一行给定n个数;表示第i个点的救援队数量
接下来m行给定u v w;表示点u到点v有一条长度为w的边
求从s到t的最短路有几条
一条路上可以集合的救援队最多有多少
输出路径
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define inc(i,j,k) for(int i=j;i<=k;i++) #define dec(i,j,k) for(int i=j;i>=k;i--) #define gcd(i,j) __gcd(i,j) #define mem(i,j) memset(i,j,sizeof(i)) const int N=2e5+5; const int mod=1e9+7; int n,m,s,t; int V[N]; struct NODE{ int to,len; }; vector <NODE> G[N]; int dis[N], num[N]; int sumV[N], pre[N]; bool vis[N]; int main() { while(~scanf("%d%d%d%d",&n,&m,&s,&t)) { inc(i,0,n-1) scanf("%d",&V[i]); inc(i,0,n-1) G[i].clear(); while(m--) { int u,v,w; scanf("%d%d%d",&u,&v,&w); G[u].push_back({v,w}); G[v].push_back({u,w}); } mem(sumV,0); sumV[s]=V[s]; // 到i点的最短路可集合sumV[i]救援队 mem(dis,INF); dis[s]=0; // 到i点的最短路长度为dis[i] mem(num,0); num[s]=1; // 到i点的最短路有num[i]条 mem(pre,-1); mem(vis,0); // pre记录路径前驱 vis标记走过 while(1) { int u, mini=INF; inc(i,0,n-1) if(!vis[i] && dis[i]<mini) mini=dis[i], u=i; if(mini==INF) break; vis[u]=1; int all=G[u].size(); inc(i,0,all-1) { NODE v=G[u][i]; if(vis[v.to]) continue; if(dis[v.to]>dis[u]+v.len) { sumV[v.to]=sumV[u]+V[v.to]; dis[v.to]=dis[u]+v.len; num[v.to]=num[u]; pre[v.to]=u; } else if(dis[v.to]==dis[u]+v.len) { num[v.to]+=num[u]; if(sumV[v.to]<sumV[u]+V[v.to]) { sumV[v.to]=sumV[u]+V[v.to], pre[v.to]=u; } } } } printf("%d %d\n",num[t],sumV[t]); stack <int> s; int c=0; while(t!=-1) s.push(t), t=pre[t], c++; while(!s.empty()) { printf("%d",s.top()); s.pop(); if(--c==0) printf("\n"); else printf(" "); } } return 0; }