zoukankan      html  css  js  c++  java
  • 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
    ",tt,C[1]/(1-A[1]));
            else 
                printf("Case %d: impossible
    ",tt);
        }
        return 0;
    }
  • 相关阅读:
    1.3.6 详解build.gradle文件——Android第一行代码(第二版)笔记
    1.3.5 详解项目中的资源——Android第一行代码(第二版)笔记
    1.3.4分析你的第一个Android程序——Android第一行代码(第二版)笔记
    1.3创建你的第一个Android项目——Android第一行代码(第二版)笔记
    1.2搭建开发环境——Android第一行代码(第二版)笔记
    1.1.3 Android应用开发特色——Android第一行代码(第二版)笔记
    函数与方法的区别
    你真的知道敏捷到底是什么吗?
    某个应用的CPU使用率居然达到100%,我该怎么办?
    异常 lock buffer failed for format 0x23
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/7610733.html
Copyright © 2011-2022 走看看