最短路的方案数+打印路径
这个题目整合了我们最短路用到的很多技能
如何统计最短路径的方案数呢,这就需要我们另外开一个全局数组
如何打印路径呢,还是开一个全局的数组,记录前一个是啥就行
简单的来说,要增加啥新的功能,直接多开全局变量就行,没必要写在优先队列里面,不好转换
题目地址
#include<bits/stdc++.h>
using namespace std;
const int N = (int)505;
int n,m,s,d;
int num[N];
// 没有说明有多少条边
struct node{
int v,w;
};
vector<node> ed[N];
vector<int> path(N,-1);
vector<int> cnt(N,0);
vector<int> shu(N,0);
void fun(){
vector<int> dis(n,0x3f3f3f3f);
vector<int> vis(n,0);
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> q;
q.push({0,s});
cnt[s] = 1;
shu[s] = num[s];
dis[s] = 0;
while(q.size()){
auto now = q.top();q.pop();
int d = now.first, u = now.second;
if(vis[u]) continue;
vis[u] = 1;
for(int i=0;i<ed[u].size();i++){
int v = ed[u][i].v, w = ed[u][i].w;
if(d+w<dis[v]){ // 这里还是很正常的最短路
dis[v] = d + w;
cnt[v] = cnt[u];
shu[v] = shu[u] + num[v];
path[v] = u;
q.push({dis[v],v});
}
else if(d+w==dis[v]){ // 如果距离相等就需要加上这条路径上的方案数
cnt[v] += cnt[u];
if(shu[v]<shu[u]+num[v]){ // 相同距离下,如果救援队的数量更多,就采取这条新的路径
path[v] = u;
shu[v] = shu[u] + num[v];
}
}
}
}
}
int main(){
cin >> n >> m >> s >> d;
for(int i=0;i<n;i++){
cin >> num[i];
}
int u,v,w;
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
ed[u].push_back({v,w});
ed[v].push_back({u,w});
}
fun();
cout << cnt[d] << " " << shu[d] << endl;
vector<int> ans;
int now = d;
while(path[now]!=-1){
ans.push_back(path[now]);
now = path[now];
}
for(int i=ans.size()-1;i>=0;i--){
cout << ans[i] << " ";
}
cout << d;
return 0;
}
要弄清楚的就是距离相同的时候,如何进行转换,距离相同的时候,救援队的数量就是我们需要考虑的因素,我们直接采取新的路径就行
可能有的疑惑是为什么路径相等的时候不再次将这个节点push到堆中,这是因为我们的堆中肯定存在这个节点了,且一定没有遍历到,这是因为我们的当前的距离是d , 而v节点的距离dis[v] == d + w,这么说dis[v]大于d,那么v节点一定存在于堆中,我们就没必要重复push进去了