题意:
有
T
T
T组测试数据,给你一个
n
n
n个点
m
m
m条边的有向带权图,选出
k
k
k个点,问你这
k
k
k个点两两之间最短路最短的是多少。这里两两之间是任意一个方向能到达即可。边权均为正数。
T
≤
5
,
n
≤
1
e
5
,
m
≤
5
e
5
,
2
≤
k
≤
n
T\leq5,n\leq1e5,m\leq5e5,2\leq k\leq n
T≤5,n≤1e5,m≤5e5,2≤k≤n。
5
5
5秒。
题解:
正解是二进制拆分加最短路。这个思路很久之前见过,当时是zxf比赛时秒的。做法是新建两个
s
s
s和
t
t
t,将选出的点分成
A
,
B
A,B
A,B两个集合,
s
s
s向
A
A
A集合所有点连边权为
0
0
0的有向边,
B
B
B集合所有点向
t
t
t连边权为
0
0
0的有向边。这样
A
A
A集合中所有点到
B
B
B集合所有点最短的最短路就变成了
s
s
s到
t
t
t的最短路。对于任意两个不同的点,它们的编号在二进制下必有至少一位不同。因此我们进行
l
o
g
n
logn
logn次分组,每次根据二进制下某一位是
0
0
0还是
1
1
1来判断这次这个点被分入
A
A
A集合还是
B
B
B集合。这样
l
o
g
n
logn
logn次最短路中得到的最小的那一个,就是最终答案。
时间复杂度 O ( T ( n + m ) l o g m l o g n ) O(T(n+m)logmlogn) O(T(n+m)logmlogn)。
当然,还有别的一些做法。
这个题是可以有一个
l
o
g
log
log的做法的,把二进制拆分省去。思路是对于每个选出的点,都求出它出发最近的选出点的距离,和其他选出点到它的最近距离。做法大概是正反图各跑一次最短路,一开始将所有选出点都作为源点。另外可能需要注意统计答案时不要选出点自己到自己的路径统计进去。有些细节我没仔细想,思路上是这样。
这个题我有一个奇怪的想法,似乎我没看到这种思路的题解或者讨论,写起来又不算简单,打算随便在这里记录一下,有人看到感兴趣的话可以和我讨论(如果那时我还没退役)。我最初想这个题的思路是和上面这个正反两遍最短路的想法有点像的,我受了 D A G DAG DAG部分分的启发,想着如果是 D A G DAG DAG,那么我们可以根据拓扑序的反序来做,维护出每一个点从它出发最近的选出点(除了自己)的距离,然后按照拓扑序的反序去做应该就行。然后推广到一般有向图,无非就是多了环的处理。我们还是想处理出每个点到最近的选出点的距离。我们先缩点,对缩点后的图求拓扑序,按照这个拓扑序的反序来处理。这里虽然缩点了,但是处理起来并不能按照缩后一个连通块为一个点来处理,还是要在没缩点之前的图上处理,缩点的目的是给在环上的点确定一个处理它的时机,让它在拓扑序合适的时候处理。对于不在环上的点,还和 D A G DAG DAG时一样处理。对于在环上的点,它们缩点后在同一个块,于是拓扑序的顺序是相同的,我们也将一个环上的点一起处理。首先先遍历它们不在环上的出边,更新它们到任意选出点的最短路,再在环上转圈来更新环内点的答案。注意一下环上只有一个选出点时不要把自己到自己的环用来更新答案就行。思路上就是这样,复杂度一个 l o g log log,写起来比上面两种都难,有点懒得写了,感觉可能会对。
另外,基于正解的讨论,就算你没想到要二进制拆分,你每次把点随机分组,多随机几次也可以弄出期望正确率较高的随机化算法。
暂无代码。