【蓝桥杯】观光铁路(SPFA算法运用于非最短路问题)

问题描述

跳蚤国正在大力发展旅游业,每个城市都被打造成了旅游景点。
  许多跳蚤想去其他城市旅游,但是由于跳得比较慢,它们的愿望难以实现。这时,小C听说有一种叫做火车的交通工具,在铁路上跑得很快,便抓住了商机,创立了一家铁路公司,向跳蚤国王请示在每两个城市之间都修建铁路。
  然而,由于小C不会扳道岔,火车到一个城市以后只能保证不原路返回,而会随机等概率地驶向与这个城市有铁路连接的另外一个城市。
  跳蚤国王向广大居民征求意见,结果跳蚤们不太满意,因为这样修建铁路以后有可能只游览了3个城市(含出发的城市)以后就回来了,它们希望能多游览几个城市。于是跳蚤国王要求小C提供一个方案,使得每只跳蚤坐上火车后能多游览几个城市才回来。 小C提供了一种方案给跳蚤国王。跳蚤国王想知道这个方案中每个城市的居民旅游的期望时间(设火车经过每段铁路的时间都为1),请你来帮跳蚤国王。
输入格式
  输入的第一行包含两个正整数n、m,其中n表示城市的数量,m表示方案中的铁路条数。
  接下来m行,每行包含两个正整数u、v,表示方案中城市u和城市v之间有一条铁路。
  保证方案中无重边无自环,每两个城市之间都能经过铁路直接或间接到达,且火车由任意一条铁路到任意一个城市以后一定有路可走。
输出格式
  输出n行,第i行包含一个实数 tBi t B i ,表示方案B中城市i的居民旅游的期望时间。你应当输出足够多的小数位数,以保证输出的值和真实值之间的绝对或相对误差不超过1e-9。
样例输入
4 5
1 2
2 3
3 4
4 1
1 3
样例输出
3.333333333333
5.000000000000
3.333333333333
5.000000000000
数据规模和约定
  对于10%的测试点,n <= 10;
  对于20%的测试点,n <= 12;
  对于50%的测试点,n <= 16;
  对于70%的测试点,n <= 19;
  对于100%的测试点,4 <= k <= n <= 21,1 <= u, v <= n。数据有梯度。

解决过程

仔细一看,这根本就不是最短路问题嘛。
让我们简化一下问题
只求 i=1 i = 1 的 情形。

问题变成,对于城市 1 1 来说,出发回到原点的期望时间是多少?

首先,要明确几件事情

引理一

对于出发点城市 1 1 来说,出发到每个子节点的概率之和(出度)与父节点到本节点的概率之和(入度)相等,且为1。
这里的出度和入度,都是借用网络流概念。
很显然,城市1即是起点也是终点。
《【蓝桥杯】观光铁路(SPFA算法运用于非最短路问题)》
也就是说,乘客一定会回到原点,即使时间是

引理二 加权平均

对于概率 p1,p2pn p 1 , p 2 … … p n 与相对应的值 x1,x2xn x 1 , x 2 … … x n
它们的平均期望应该是

x¯=ni=1pixini=1pi x ¯ = ∑ i = 1 n p i ∗ x i ∑ i = 1 n p i

这个平均期望对应的概率是

p=i=1npi p = ∑ i = 1 n p i

对于某个节点 k k
《【蓝桥杯】观光铁路(SPFA算法运用于非最短路问题)》
到达 k k 的平均期望就是 x¯ x ¯ ,到达 k k 的概率就是 p p
(如果以父节点的时间计算的话k的平均期望就是 x¯+ni=1pi1ni=1pi=x¯+1 x ¯ + ∑ i = 1 n p i ∗ 1 ∑ i = 1 n p i = x ¯ + 1 )

而这道题中有这么一个性质

性质:子节点不会影响父节点,父节点只会影响子节点。

这个性质可能看起来不怎么样。
让我们回想一下SPFA算法对Bellman – Ford算法的最大优化在哪?
对某个节点松弛操作后,只有这个节点的子节点受到了影响
对了
这就是SPFA的核心思想

于是我们可以得出求解城市1的了

步骤

  1. 建立两个数组,概率 p[i] p [ i ] ,时间 x[i] x [ i ] , i i 为城市节点。显然 p[1]=100%=1,x[1]=0 p [ 1 ] = 100 % = 1 , x [ 1 ] = 0
  2. 城市1入队,指针 i i 指向城市1.
  3. 除了城市1,如果 p[i]x[i]<1E9(109) p [ i ] ∗ x [ i ] < 1 E − 9 ( 也 就 是 10 − 9 ) 那么跳到步骤7。否则继续执行步骤4。
  4. 计算子节点的数量 ni n i 和平分给子节点的概率 P=p[i]ni P = p [ i ] n i
  5. 对于所有在队列内的子节点 k k (如果城市1是子节点那么也算在队列内,虽然实际并不在内),计算并赋值加权平均 x[k]=(x[i]+1)P+x[k]p[k]P+p[k] x [ k ] = ( x [ i ] + 1 ) ∗ P + x [ k ] ∗ p [ k ] P + p [ k ] 和概率 p[k]=P+p[k] p [ k ] = P + p [ k ]
  6. 将所有在队列外的子节点 j j 入队(城市1除外)。对于每一个 j j ,赋值 p[j]=P,x[j]=x[i]+1 p [ j ] = P , x [ j ] = x [ i ] + 1
  7. 对于本身节点,赋值 p[i]=0,x[i]=0 p [ i ] = 0 , x [ i ] = 0 ,出队,指针 i i 移向下一位。
  8. 直到队列为空。
解释

第3步.这是搜索的边界条件。可以证明,时间的增长速度比概率的衰减速度要慢的多,对最终结果的影响有限。当然,存在有更精确的边界条件。不是唯一的。
第7步.这是保证,在队列内的概率总和不会大于100%。也就是说,回到城市1的概率不会大于100%。

于是我们就获得了单源的算法。
所以,对于所有的 i i ,都进行一次上面的类SPFA操作,就可以求得答案了。
由上面的边界条件可以看到,在最理想的情况下,一个点要经历估算至少 log210930 log 2 ⁡ 10 9 ≈ 30 次入队才会排除
那么算法时间 O(kE)O(V)=O(kV2) O ( k E ) ∗ O ( V ) = O ( k V 2 ) (k为节点平均入队次数, 30 ≥ 30 ,E为边数,V为节点数。由无重边无自环,所以E=V)
还算是理想的效率.

    原文作者:旅游交通路线问题
    原文地址: https://blog.csdn.net/weixin_40839812/article/details/79769757
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞