Travel [BFS]

Travel [BFS]

话说这道题并没有找到提交的地方…就不写代码了[滑稽]

题目描述

给定一张n 个点的完全图,边都是无向的。

一共有n(n−1)/2 条边,其中有m 条边的边权是a,剩下的边边权都是b。

求1 到n 的最短路。

数据范围

2 ≤ n ≤ 100000; 0 ≤ m ≤ 500000

题解

一 初步分析

这是一张完全图,也就是说任意两点之间必有一条路相连。

如果 L e n [ 1 > n ] == a ,那么最短路里面肯定不能再包含 a ,即 L e n a

同理可得 L e n [ 1 > n ] == b 的情况。

所以最短路一定只包含 a b

现在只用把含 a 和含 b 的边单独提出来跑最短路,并在两个答案里面取最小值即可。

二 如何跑最短路

对于第一张图(边权全部为 a 的图),边数并不是很多, O ( m ) 时间复杂度内就可以BFS跑完。(dijkstra的时间复杂度是 ( n + m ) l o g   n

对于第二张图(边权全部为 b 的图),显然不能够直接用BFS跑。

我们考虑BFS的执行过程:BFS是把队列中的每一个点延伸出去的边依次讨论,并把没在队列中的点加入队中,很多时间浪费在了没有用的边上。实际上,这么多条边里面最多只有 n 条边是有用的,也就是说,每个点只需要入队一次。如果避免了重复进队的点和无用的边,就可以快速找出最短路。

现在的任务是,精确地找出连向最短路的点

由分析可得,边权为 b 的边(简称 b 边)最多会被分为 m 个部分(考虑从一个点辐射状发出的边中,有 m a 边,剩余的全是 b 边;其余情况同样如此)(当有 a 边相邻时, b 边会被分为 < m 个部分;这并没有什么影响)

这里写图片描述

我们给每条边编号(没有特别的顺序)。

设一个 b 边的区间为 [ L , R ] f a [ i ] 表示编号>=i,且不在队列中的最小编号。初始时 f a [ i ] = i ,类似于并查集。注意:这与并查集中 f a [ i ] 的定义有所不同。

按照边的编号顺序,对每一个区间进行如下操作:

  1. int x=getfa(L);

  2. while(x<=R){x入队; 进行最短路的操作; fa[x]=x+1; x=getfa(x+1);}

    I. fa[x]=x+1是因为x+1尚未入队。

    II. 最后一句表示的是x往后跳。精确地找出在最短路上的点。

然后我们就可以愉快地得出第二张图的最短路了。

最后比较两张图的答案,输出最小值。

猜你喜欢

转载自blog.csdn.net/ArliaStark/article/details/81347189
BFS