第二道黑题祭~~~
P5304 [GXOI/GZOI2019]旅行者
(P5304 [GXOI/GZOI2019]旅行者)
题目描述
J
J
J 国有
n
n
n 座城市,这些城市之间通过
m
m
m 条单向道路相连,已知每条道路的长度。
一次,居住在
J
J
J 国的
R
a
i
n
b
o
w
Rainbow
Rainbow 邀请
V
a
n
i
Vani
Vani 来作客。不过,作为一名资深的旅行者,
V
a
n
i
Vani
Vani 只对
J
J
J 国的
k
k
k 座历史悠久、自然风景独特的城市感兴趣。
为了提升旅行的体验,
V
a
n
i
Vani
Vani 想要知道他感兴趣的城市之间「两两最短路」的最小值(即在他感兴趣的城市中,最近的一对的最短距离)。
也许下面的剧情你已经猜到了——
V
a
n
i
Vani
Vani 这几天还要忙着去其他地方游山玩水,就请你帮他解决这个问题吧。
输入格式
每个测试点包含多组数据,第一行是一个整数
T
T
T,表示数据组数。注意各组数据之间是互相独立的。
对于每组数据,第一行包含三个正整数
n
,
m
,
k
n,m,k
n,m,k 表示 J 国的 nn 座城市(从
1
∼
n
1 \sim n
1∼n 编号),
m
m
m 条道路,
V
a
n
i
Vani
Vani 感兴趣的城市的个数
k
k
k。
接下来
m
m
m 行,每行包括
3
3
3 个正整数
x
,
y
,
z
x,y,z
x,y,z,表示从第
x
x
x 号城市到第
y
y
y 号城市有一条长度为
z
z
z 的单向道路。注意
x
,
y
x,y
x,y 可能相等,一对
x
,
y
x,y
x,y 也可能重复出现。
接下来一行包括
k
k
k 个正整数,表示
V
a
n
i
Vani
Vani 感兴趣的城市的编号。
输出格式
输出文件应包含
T
T
T 行,对于每组数据,输出一个整数表示
k
k
k 座城市之间两两最短路的最小值。
输入输出样例
输入
2
6 7 3
1 5 3
2 3 5
1 4 3
5 3 2
4 6 5
4 3 7
5 6 4
1 3 6
7 7 4
5 3 10
6 2 7
1 2 6
5 4 2
4 3 4
1 7 3
7 2 4
1 2 5 3
输出
5
6
说明/提示
样例解释
对于第一组数据,
1
1
1 到
3
3
3 最短路为
5
5
5;
1
1
1 到
6
6
6 最短路为
7
7
7;
3
,
6
3,6
3,6 无法到达,所以最近的两点为
1
,
3
1,3
1,3,最近的距离为
5
5
5。
对于第二组数据,
1
1
1 到
2
2
2 最短路为
6
6
6;
5
5
5 到
3
3
3 最短路为
6
6
6;其余的点均无法互相达,所以最近的两点为
1
,
2
1,2
1,2 和
5
,
3
5,3
5,3,最近的距离为
6
6
6。
数据范围
2
≤
k
≤
n
,
1
≤
x
,
y
≤
n
,
1
≤
z
≤
2
×
1
0
9
,
T
≤
52
≤
k
≤
n
,
1
≤
x
,
y
≤
n
,
1
≤
z
≤
2
×
1
0
9
,
T
≤
5
。
2 \le k \le n,1 \le x,y \le n,1 \le z \le 2 \times 10^9,T ≤52≤k≤n,1≤x,y≤n,1≤z≤2×10^9 ,T≤5。
2≤k≤n,1≤x,y≤n,1≤z≤2×109,T≤52≤k≤n,1≤x,y≤n,1≤z≤2×109,T≤5。
测试点编号
n
n
n 的规模
m
m
m 的规模 约定
1
≤
1
,
000
≤
5
,
000
\le 1,000 \le 5,000
≤1,000≤5,000 无
2
≤
1
,
000
≤
5
,
000
\le 1,000 \le 5,000
≤1,000≤5,000 无
3
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 保证数据为有向无环图
4
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 保证数据为有向无环图
5
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 保证数据为有向无环图
6
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 无
7
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 无
8
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 无
9
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 无
10
≤
100
,
000
≤
500
,
000
\le 100,000 \le 500,000
≤100,000≤500,000 无
思路:
类似20191029 csp-s模拟T3(多源最短路)
但是为了避免对顶的情况,要在正反两个图上各跑一次
D
i
j
k
s
t
r
a
Dijkstra
Dijkstra。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
long long in{
long long s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const long long A=1e6+5;
long long t;
long long n,m,k;
long long u,v,w;
long long xx[A],yy[A],ww[A];
long long head[A],tot=1;
struct Road{
long long nex,to,w;
}road[A];
inline void ljb(long long x,long long y,long long w){road[++tot]={head[x],y,w};head[x]=tot;}
long long p[A];
long long res=1e18;
long long s[A][2],f[A][2];
bool ex[A][2];
inline void djk(long long d){
for(long long i=1;i<=n;i++) s[i][d]=1e18,ex[i][d]=0;
priority_queue <pair<long long,long long> > q;
for(long long i=1;i<=k;i++){
s[p[i]][d]=0,f[p[i]][d]=p[i];
q.push(make_pair(0,p[i]));
}
while(!q.empty()){
long long x=q.top().second;q.pop();
if(ex[x][d]) continue;
ex[x][d]=1;
for(long long y=head[x];y;y=road[y].nex){
long long z=road[y].to,w=road[y].w;
if(s[z][d]>s[x][d]+w){
s[z][d]=s[x][d]+w,f[z][d]=f[x][d];
q.push(make_pair(-s[z][d],z));
}
}
}
}
inline void clean(){
for(long long i=1;i<=n;i++)head[i]=0;
tot=0;
}
signed main(){
t=in;
while(t--){
res=1e18;
n=in,m=in,k=in;
clean();
for(long long i=1;i<=m;i++){
u=in,v=in,w=in;
xx[i]=u,yy[i]=v,ww[i]=w;
ljb(u,v,w);
}
for(long long i=1;i<=k;i++)
p[i]=in;
djk(0);
clean();
for(long long i=1;i<=m;i++)
ljb(yy[i],xx[i],ww[i]);
djk(1);
for(long long i=1;i<=m;i++){
long long x=xx[i],y=yy[i],w=ww[i];
if(f[x][0]&&f[y][1]&&f[x][0]!=f[y][1])
res=min(res,s[x][0]+s[y][1]+w);
}
printf("%lld\n",res);
}
return 0;
}