题目
题意: 给定n个点、m条边的图,求从st到ed的最短路。记录最短路的路径,如果最短路不止一条,则记录点权和最大的那一条,题目保证该路径唯一。另,输出最短路路径的数量。
思路: Dijkstra,额外维护几个数组即可。
如果dist[j] > dist[u] + w, cnt[j] = cnt[u]. (因为j由u转移过来)
如果dist[j] == dist[u] + w,cnt[j] += cnt[u] (因为j多了从u来的路)
另外,相等时需要判断是否点权和更大,依此来更新。
时间复杂度: O(mlogm)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 502;
struct node{
int v;
int w;
node()
{
}
node(int a,int b)
{
v = a,w = b;
}
};
vector<node> va[N];
int a[N];
int n,m,k,T;
int st,ed;
int pre[N];
int dist[N];
bool vis[N];
int cnt[N];
int sum[N];
void Dij(int st)
{
memset(dist,0x3f,sizeof(dist));
priority_queue<PII,vector<PII>,greater<PII> > q;
q.push({0,st});
cnt[st] = 1;
sum[st] = a[st];
dist[st] = 0;
while(q.size())
{
PII tmp = q.top(); q.pop();
int u = tmp.second;
// cout<<u<<":"<<q.size()<<"?"<<endl;
if(vis[u]) continue;
vis[u] = 1;
for(int i=0;i<va[u].size();++i)
{
int j = va[u][i].v;
int w = va[u][i].w;
// cout<<u<<":"<<dist[u]<<" "<<w<<endl;
if(dist[j] > dist[u] + w)
{
dist[j] = dist[u] + w;
cnt[j] = cnt[u];
sum[j] = sum[u] + a[j];
pre[j] = u;
q.push({dist[j],j});
}
else if(dist[j] == dist[u] + w)
{
cnt[j] += cnt[u];
if(sum[j] < sum[u] + a[j])
{
sum[j] = sum[u] + a[j];
pre[j] = u;
}
}
}
}
}
void solve()
{
memset(pre,-1,sizeof(pre));
cin>>n>>m>>st>>ed;
for(int i=0;i<n;++i) cin>>a[i];
while(m--)
{
int x,y,z; cin>>x>>y>>z;
va[x].push_back({y,z});
va[y].push_back({x,z});
}
Dij(st);
cout<<cnt[ed]<<" "<<sum[ed]<<"\n";
vector<int> res;
int now = ed;
while(now != -1)
{
res.push_back(now);
now = pre[now];
}
reverse(res.begin(),res.end());
for(int i=0;i<res.size();++i)
{
if(i) cout<<' '; cout<<res[i];
}
}
int main(void)
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}
/*
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
*/