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

##问题描述
跳蚤国正在大力发展旅游业,每个城市都被打造成了旅游景点。
  许多跳蚤想去其他城市旅游,但是由于跳得比较慢,它们的愿望难以实现。这时,小C听说有一种叫做火车的交通工具,在铁路上跑得很快,便抓住了商机,创立了一家铁路公司,向跳蚤国王请示在每两个城市之间都修建铁路。
  然而,由于小C不会扳道岔,火车到一个城市以后只能保证不原路返回,而会随机等概率地驶向与这个城市有铁路连接的另外一个城市。
  跳蚤国王向广大居民征求意见,结果跳蚤们不太满意,因为这样修建铁路以后有可能只游览了3个城市(含出发的城市)以后就回来了,它们希望能多游览几个城市。于是跳蚤国王要求小C提供一个方案,使得每只跳蚤坐上火车后能多游览几个城市才回来。 小C提供了一种方案给跳蚤国王。跳蚤国王想知道这个方案中每个城市的居民旅游的期望时间(设火车经过每段铁路的时间都为1),请你来帮跳蚤国王。
输入格式
  输入的第一行包含两个正整数n、m,其中n表示城市的数量,m表示方案中的铁路条数。
  接下来m行,每行包含两个正整数u、v,表示方案中城市u和城市v之间有一条铁路。
  保证方案中无重边无自环,每两个城市之间都能经过铁路直接或间接到达,且火车由任意一条铁路到任意一个城市以后一定有路可走。
输出格式
  输出n行,第i行包含一个实数 t B i t_{B_i} tBi,表示方案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 i=1的 情形。
###问题变成,对于城市 1 1 1来说,出发回到原点的期望时间是多少?
首先,要明确几件事情
####引理一
对于出发点城市 1 1 1来说,出发到每个子节点的概率之和(出度)与父节点到本节点的概率之和(入度)相等,且为1。
这里的出度和入度,都是借用网络流概念。
很显然,城市1即是起点也是终点。
这里写图片描述
也就是说,乘客一定会回到原点,即使时间是 ∞ \infty
####引理二 加权平均
对于概率 p 1 , p 2 … … p n p_1,p_2……p_n p1,p2pn与相对应的值 x 1 , x 2 … … x n x_1,x_2……x_n x1,x2xn
它们的平均期望应该是
x ˉ = ∑ i = 1 n p i ∗ x i ∑ i = 1 n p i \bar x ={ \sum_{i=1}^{n} p_i*x_ i \over \sum_{i=1}^{n} p_i} xˉ=i=1npii=1npixi
这个平均期望对应的概率是 p = ∑ i = 1 n p i p=\sum_{i=1}^{n} p_i p=i=1npi

对于某个节点 k k k
这里写图片描述
到达 k k k的平均期望就是 x ˉ \bar x xˉ,到达 k k k的概率就是 p p p
(如果以父节点的时间计算的话k的平均期望就是 x ˉ + ∑ i = 1 n p i ∗ 1 ∑ i = 1 n p i = x ˉ + 1 \bar x+{ \sum_{i=1}^{n} p_i*1 \over \sum_{i=1}^{n} p_i}=\bar x+1 xˉ+i=1npii=1npi1=xˉ+1)

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

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

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

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

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值