hdu 4035 经典概率dp求期望

本文介绍了一种使用全期望公式计算从特定节点出发逃走的期望路径长度的方法,并详细推导了非叶子节点及叶子节点处的期望计算公式。通过定义随机变量X为从节点i开始逃走所走过的边数,最终推导出了适用于所有节点的通用公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求期望要用到全期望公式来来分类讨论:

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) );
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值