说在前面
之前写了几道简单期望,感觉期望不过如此
然后就被HDU4035和HDU4089打脸了…….
看着别人的题解推公式都能推一个晚上,me好弱啊qwq
题目
…话说HDU原来的站挂掉了,现在的新站要在中间加一个split???
http://acm.split.hdu.edu.cn/
HDU4035传送门
题意
有一颗n个节点的树,n-1条边,根节点为1
在每个节点i都有概率发生以下事件:
1.被传送回1号节点—————————————概率为K[i]
2.找到出口并退出这棵树———————————概率为E[i]
3.沿着与i相连的边进入下一个点(可以返回父节点)
询问从1开始走到退出平均要走的步数
注:1号节点是没有出口的,1号节点也没有父节点
解法
(就对比着别人的推导自己又整理了一遍而已)
对于点i,我们设F[i]为从这个点开始,在退出时期望走出的边数
如果点i是叶子节点,那么有:
F[i]=F[1]∗K[i]+0∗E[i]+(1−K[i]−E[i])∗(F[fa]+1)
F
[
i
]
=
F
[
1
]
∗
K
[
i
]
+
0
∗
E
[
i
]
+
(
1
−
K
[
i
]
−
E
[
i
]
)
∗
(
F
[
f
a
]
+
1
)
(叶子节点的下一步可以是1号节点,也可以退出,也可以返回父节点)
如果点i不是叶子节点,那么有:
F[i]=F[1]∗K[i]+0∗E[i]+(1−K[i]−E[i]m∗(F[fa]+1+∑(F[child]+1)))
F
[
i
]
=
F
[
1
]
∗
K
[
i
]
+
0
∗
E
[
i
]
+
(
1
−
K
[
i
]
−
E
[
i
]
m
∗
(
F
[
f
a
]
+
1
+
∑
(
F
[
c
h
i
l
d
]
+
1
)
)
)
(m代表的是i节点所连的边数,下同。非叶子节点的下一步,可以返回1号节点,也可以退出,也可以返回父节点或者走向任意一个子节点)
我们发现,两种F[i]都可以被表示成这样的形式
F[i]=F[1]∗A[i]+F[fa]∗B[i]+C[i]
F
[
i
]
=
F
[
1
]
∗
A
[
i
]
+
F
[
f
a
]
∗
B
[
i
]
+
C
[
i
]
设点对[i,j],其中i是j的父亲
那么有:
⇒F[j]=F[1]∗A[j]+B[j]∗F[i]+C[j]⇒(∑F[j])=(∑A[j])∗F[1]+(∑B[j])∗F[i]+(∑C[j])
⇒
F
[
j
]
=
F
[
1
]
∗
A
[
j
]
+
B
[
j
]
∗
F
[
i
]
+
C
[
j
]
⇒
(
∑
F
[
j
]
)
=
(
∑
A
[
j
]
)
∗
F
[
1
]
+
(
∑
B
[
j
]
)
∗
F
[
i
]
+
(
∑
C
[
j
]
)
将以上式子带入对于i点的”非叶节点F[i]推导式”,得出:
⇒F[i]=F[1]∗K[i]+(1−K[i]−E[i]m)∗(F[fa]+m+(∑A[j])∗F[1]+(∑B[j])∗F[i]+(∑C[j]))
⇒
F
[
i
]
=
F
[
1
]
∗
K
[
i
]
+
(
1
−
K
[
i
]
−
E
[
i
]
m
)
∗
(
F
[
f
a
]
+
m
+
(
∑
A
[
j
]
)
∗
F
[
1
]
+
(
∑
B
[
j
]
)
∗
F
[
i
]
+
(
∑
C
[
j
]
)
)
通过移项,把F[i]移动到等式的左边,最终可以得到一个式子(我实在是不想写LaTeX了…手推一下吧qwq)
令
D[i]=1−1−K[i]−E[i]m∗(∑B[j])
D
[
i
]
=
1
−
1
−
K
[
i
]
−
E
[
i
]
m
∗
(
∑
B
[
j
]
)
那么,对于F[i],他的A[i],B[i],C[i]就是:
A[i]=(K[i]+1−K[i]−E[i]m∗(∑A[j])) / D[i]B[i]=(1−K[i]−E[i]m) / D[i]C[i]=((1−K[i]−E[i])+1−K[i]−E[i]m∗(∑C[j])) / D[i]
A
[
i
]
=
(
K
[
i
]
+
1
−
K
[
i
]
−
E
[
i
]
m
∗
(
∑
A
[
j
]
)
)
/
D
[
i
]
B
[
i
]
=
(
1
−
K
[
i
]
−
E
[
i
]
m
)
/
D
[
i
]
C
[
i
]
=
(
(
1
−
K
[
i
]
−
E
[
i
]
)
+
1
−
K
[
i
]
−
E
[
i
]
m
∗
(
∑
C
[
j
]
)
)
/
D
[
i
]
也就是说,对于每个点的A[i],B[i],C[i]值,我们都是可以由已知条件和子节点的A,B,C值求出来的,而叶节点的A,B,C值可以直接算(参见我的第一个公式”叶节点F[i]推导式”)
从下往上推,最终我们可以将F[1]用A,B,C表示出来。
那么最后答案就是
⇒F[1]=A[1]∗F[1]+B[1]∗F[fa]+C[1] (fa[1]==0)⇒ Ans=C[1]1−A[1]
⇒
F
[
1
]
=
A
[
1
]
∗
F
[
1
]
+
B
[
1
]
∗
F
[
f
a
]
+
C
[
1
]
(
f
a
[
1
]
==
0
)
⇒
A
n
s
=
C
[
1
]
1
−
A
[
1
]
下面是自带大常数的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const double eps = 1e-9 ;//精度至少1e-9才能过
int T , N , tp , head[10005] , deg[10005] ;
double K[10005] , E[10005] , A[10005] , B[10005] , C[10005] ;
struct Path{
int pre , to ;
}p[200005] ;
template <typename T>
int dcmp( T x ){
if( x < 0 ) x = -x ;
if( x <= eps && x >= -eps ) return 0 ;
return x > 0 ;
}
void In( int t1 , int t2 ){
p[++tp].pre = head[t1] ;
p[ head[t1] = tp ].to = t2 ;
}
void dfs( int u , int f ){
double sumB = 0.0 ;
A[u] = K[u] ; C[u] = ( 1 - K[u] - E[u] ) ; B[u] = C[u] / deg[u] ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
dfs( v , u ) ;
A[u] += ( 1 - K[u] - E[u] ) / deg[u] * A[v] ;
C[u] += ( 1 - K[u] - E[u] ) / deg[u] * C[v] ;
sumB += ( 1 - K[u] - E[u] ) / deg[u] * B[v] ;
}
A[u] /= ( 1 - sumB ) ;
C[u] /= ( 1 - sumB ) ;
B[u] /= ( 1 - sumB ) ;
}
void clear(){
memset( head , 0 , sizeof( head ) ) ;
memset( deg , 0 , sizeof( deg ) ) ;
memset( A , 0 , sizeof( A ) ) ;
memset( B , 0 , sizeof( B ) ) ;
memset( C , 0 , sizeof( C ) ) ;
tp = 0 ;
}
int main(){
scanf( "%d" , &T ) ;
for( int te = 1 ; te <= T ; te ++ ){
clear() ;
scanf( "%d" , &N ) ;
for( int i = 1 , u , v ; i < N ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
In( u , v ) ; In( v , u ) ;
deg[u] ++ ; deg[v] ++ ;
}
for( int i = 1 ; i <= N ; i ++ ){
scanf( "%lf%lf" , &K[i] , &E[i] ) ;
K[i] /= 100.0 ; E[i] /= 100.0 ;
}
dfs( 1 , -1 ) ;
printf( "Case %d: " , te ) ;
if( dcmp( 1 - A[1] ) == 0 ){
puts( "impossible" ) ;
}else printf( "%f\n" , C[1] / ( 1 - A[1] ) ) ;
}
}