题目意思
题目链接
寒假到了,
n
n
n 头牛都要去参加一场在编号为
x
x
x 的牛的农场举行的派对,农场之间有
m
m
m 条有向路,每条路都有一定的长度。
每头牛参加完派对后都必须回家,无论是去参加派对还是回家,每头牛都会选择最短路径,求这 n n n 头牛的最短路径(一个来回)中最长的一条路径长度。
样例输入
4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3
样例输出
10
解释
思路
可以发现,从 x x x 点返回 n n n 个点的方式可以用单源最短路的方式解决。为了解决从多个点来到 x x x 号点的情况,可以考虑建一个反向图,再跑一遍单源最短路,从而统计出两次所耗费的时间和。
代码
#include<bits/stdc++.h>
using namespace std;
struct edge{
int to,w;
bool operator <( const edge &x )const {
return x.w < w;
}
}e[500005];
int head[500005],en,nex[500005];
bool v[500005];
void add(int x,int y,int ww){
nex[++en] = head[x];
head[x] = en;
e[en].to = y;
e[en].w = ww;
return;
}
int kk[500005],kk1[500005];
struct edge1{
int to,w;
bool operator <( const edge1 &x )const {
return x.w < w;
}
}e1[500005];
int head1[500005],en1,nex1[500005];
bool v1[500005];
void add1(int x,int y,int ww){
nex1[++en1] = head1[x];
head1[x] = en1;
e1[en1].to = y;
e1[en1].w = ww;
return;
}
int main() {
int n,m,s;
scanf("%d%d%d",&n,&m,&s);
for(int i = 1;i <= m;i++) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add1(v,u,w);
}
for(int i = 1;i <= n;i++) {
kk[i] = pow(2,31) - 1;
kk1[i] = pow(2,31) - 1;
}
kk[s] = 0;
priority_queue<edge>q;
q.push((edge){s,0});
while(!q.empty()) {
edge ssoi = q.top();
q.pop();
int minv = ssoi.to;
v[minv] = true;
for(int j = head[minv];j;j = nex[j]){
if(!v[e[j].to]) {
if(kk[e[j].to] > kk[minv] + e[j].w) {
kk[e[j].to] = kk[minv] + e[j].w;
q.push((edge){e[j].to,kk[e[j].to]});
}
}
}
}
//
kk1[s] = 0;
priority_queue<edge1>q1;
q1.push((edge1){s,0});
while(!q1.empty()) {
edge1 ssoi = q1.top();
q1.pop();
int minv = ssoi.to;
v1[minv] = true;
//printf("%lld:",minv);
for(int j = head1[minv];j;j = nex1[j]){
//printf("%lld %lld %lld %lld\n",e1[j].to,kk1[e1[j].to],kk1[minv],e1[j].w);
if(!v1[e1[j].to]) {
if(kk1[e1[j].to] > kk1[minv] + e1[j].w) {
kk1[e1[j].to] = kk1[minv] + e1[j].w;
q1.push((edge1){e1[j].to,kk1[e1[j].to]});
}
}
}
}
for(int i = 1;i <= n;i++) kk[i] += kk1[i];
sort(kk + 1,kk + n + 1);
printf("%lld\n",kk[n]);
}