caioj1275&&hdu4035: 概率期望值6:迷宫

期望的大难题,%%ZZZ大佬的解释,不得不说这是一道好题(然而膜题解都没完全看懂,然后就去烦ZZZ大佬)

简单补充几句吧,tmp的理解是个难点,除以tmp的原因是,当我们化简时,子节点也有一个B*f[父节点],这个时候我们化简不掉,怎么办?直接将他放到等式的左边,和f[父节点]合起来,(1-(1-ki-ei)/m*∑(Bj)),这里1就是原来的父节点,然后(1-ki-ei)/m是到这个子节点的概率,乘以Bj。

这是一道树形dp,核心思想是列出dp方程用逆推的方法往前求,将这道图论题转化为数学模型化简
首先这个图有n个点,n-1条边,且两点之间仅有一条边,那么这个图实际上就是一棵树
对于点i:
设f(i)表示在结点i处,要走出迷宫所要走的边数的期望。f(1)即为所求。

若点i是叶子节点,则:
f(i)=ki*f(1)+ei*0+(1-ki-ei)*(f(fa)+1)
f(i)=ki*f(1)+(1-ki-ei)*f(fa)+(1-ki-ei) 叶子式

若点i非叶子节点,则他有父亲节点fa,和若干个儿子节点son:
f(i)=ki*f(1)+ei*0+(1-ki-ei)/m *(f(fa)+1) + (1-ki-ei)/m * ∑(f(son)+1)
f(i)=ki*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei)/m*∑(f(son))+(1-ki-ei); 非叶子式
(∑符号是求和的意思,也就是把所有的孩子加起来)

从公式可知求f(i)需要求到f(fa),f(son)
但这是很难求到的,因为要一直往上求,直到f(1),我们要求f(1)来着

假设非叶子节点i是j的父亲
设 tmp*f(i)=Ai*f(1)+Bi*f(fa)+Ci; 我们把这个作为基本式 ,tmp是我们要除掉的系数,先不管他

在非叶子节点中:

f(son) = Aj*f(1)+Bj*f(i)+Cj;
∑(f(son))=∑(Aj*f(1)+Bj*f(i)+Cj);

代入非叶子式得
f(i)=ki*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei)/m*∑(Aj*f(1)+Bj*f(i)+Cj)+(1-ki-ei);
化为基本式的形式得:
(1-(1-ki-ei)/m*∑(Bj))*f(i)=(ki+(1-ki-ei)/m*∑(Aj))*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei+(1-ki-ei)/m*∑(cj));

代入基本式得:
tmp= (1-(1-ki-ei)/m*∑(Bj))
Ai=(ki+(1-ki-ei)/m*∑(Aj))/tmp
Bi=(1-ki-ei)/m/tmp
Ci=(1-ki-ei+(1-ki-ei)/m*∑(cj))/tmp

观察到 Ai,Bi,Ci 只与j有关的Aj,Bj,Cj 和 与i有关的ki,ei 有关
所以从可以叶子开始逆推得到A1,B1,C1

在叶子节点中 易得:
Ai=ki;
Bi=(1-ki-ei);
Ci=(1-ki-ei);

而f(1)=A1*f(1)+B1*0+C1;//1的父亲是0
f(1)=C1/(1-A1);
若A1趋近于1则无解

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-9;
struct node
{
    int x,y,next;
}a[21000];int last[11000],len;
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
double k[11000],e[11000];
double A[11000],B[11000],C[11000];
int tot[11000];
bool dfs(int x,int fa)
{
    A[x]=k[x]; 
    B[x]=(1-k[x]-e[x])/tot[x];
    C[x]=1-k[x]-e[x];

    double tmp=0;
    for(int i=last[x];i;i=a[i].next)
    {
        int y=a[i].y;
        if(y!=fa)
        {
            if(dfs(y,x)==false)return false;
            
            A[x]+=(1-k[x]-e[x])/tot[x] *A[y];
            C[x]+=(1-k[x]-e[x])/tot[x] *C[y];
            tmp +=(1-k[x]-e[x])/tot[x] *B[y];
        }
    }
    if(fabs(tmp-1)<eps)return false;
    A[x]/=(1-tmp);
    B[x]/=(1-tmp);
    C[x]/=(1-tmp);  
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int tt=1;tt<=T;tt++)
    {
        int n,x,y;
        scanf("%d",&n);
        len=0;memset(last,0,sizeof(last));
        memset(tot,0,sizeof(tot));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            ins(x,y);ins(y,x);
            tot[x]++;tot[y]++;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&k[i],&e[i]);
            k[i]/=100;e[i]/=100;
        }
        
        if(dfs(1,0)==true&&fabs(1-A[1])>eps)
            printf("Case %d: %.6lf\n",tt,C[1]/(1-A[1]));
        else 
            printf("Case %d: impossible\n",tt);
    }
    return 0;
}
posted @ 2017-09-29 13:58  AKCqhzdy  阅读(161)  评论(0编辑  收藏  举报