求期望要用到全期望公式来来分类讨论:
k[i]:表示死掉回到1的概率
e[i]:表示成功逃走的概率
那么我们设定随机变量X:在节点i处开始,逃走所走的边数
那么E[i]就是从节点i开始,要逃走的边数的期望
如果i是叶子节点:
E[i] = k[i]*E[1] + e[i]*0 + (1-k[i]-e[i])*(E(parent(i))+1); (1)
如果i不是叶子节点:
与i相连的节点的总数为m,j是i的孩子节点
E[i] = k[i]*E[1] + e[i]*0 + (1-k[i]-e[i])/m*(E(parent(i))+1) + (1-k[i]-e[i])/m*sum(E[j]+1); (2)
为了简化计算过程,我们设Ai = k[i] , Bi = (1-k[i]-e[i])/m , Ci = Bi*sum(E[j]+1)+Bi;
那么E[i] = Ai*E[1] + Bi*E[p]+ Ci; (3)
导出E[j] = Aj*E[1] + Bj*E[i] + Cj; (4)
进而得到sum(E[j]) = sum ( Aj*E[1] + Bj*E(i) + Cj ) (5)
把(5)代入到(3)中得到
E[i] = Ai*E[1] + Bi*E[p] + Bi*sum(Aj*E[1] + Bj*E[i] + Cj + 1 ) + Bi (6)
=>(1-(1-ki-ei)/m*SUM(Bj))*E(i)=(ki+(1-ki-ei)/m*SUM(Aj))*E(1)+(1-ki-ei)/m *E(father)+(1-ki-ei+(1-ki-ei)/m*SUM(cj));
所以与上述2式对比得到:
Ai=(ki+(1-ki-ei)/m*SUM(Aj)) / (1-(1-ki-ei)/m*SUM(Bj))
Bi=(1-ki-ei)/m / (1-(1-ki-ei)/m*SUM(Bj))
Ci=(1-ki-ei+(1-ki-ei)/m*SUM(cj)) / (1-(1-ki-ei)/m*SUM(Bj))
所以Ai,Bi,Ci只与i的孩子Aj,Bj,Cj和本身ki,ei有关
于是可以从叶子开始逆推得到A1,B1,C1
在叶子节点:
Ai=ki;
Bi=(1-ki-ei);
Ci=(1-ki-ei);
而E(1)=A1*E(1)+B1*0+C1;
=>E(1)=C1/(1-A1);
当A趋近于1时,那么无解,精度卡到1e-9才能过
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAX 10007
#define eps 1e-9
using namespace std;
int t,n,x,y;
double k[MAX],e[MAX],A,B,C;
struct Edge
{
int v,next;
}edge[MAX<<1];
int head[MAX];
int cc;
void add ( int u , int v )
{
edge[cc].v = v;
edge[cc].next = head[u];
head[u] = cc++;
}
void dfs ( int u , int p )
{
double a,b,c,t;
a = b = c = 0.0;
int m = 0;
for ( int i = head[u] ; ~i ; i = edge[i].next )
{
int v = edge[i].v;
if ( v == p ) continue;
dfs ( v , u );
a += A;
b += B;
c += C;
m++;
}
if ( p != -1 ) m++;
t = (1-k[u]-e[u])/m;
A = (k[u]+t*a)/(1-t*b);
B = t/(1-t*b);
C = (1-k[u]-e[u]+t*c)/(1-t*b);
}
int main ( )
{
int Case = 1;
scanf ( "%d" , &t );
while ( t-- )
{
cc = 0;
memset ( head , -1 , sizeof ( head ) );
scanf ( "%d" , &n );
for ( int i = 1 ; i < n ; i++ )
{
scanf ( "%d%d" , &x , &y );
add ( x , y );
add ( y , x );
}
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: " , Case++ );
if ( fabs( A-1 ) < eps )
puts ( "impossible");
else printf ( "%.6lf\n" , C/(1-A) );
}
}