zoukankan      html  css  js  c++  java
  • 借助树的概率dp(期望)+数学-好题-hdu-4035-Maze

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4035

    题目意思:

    有n个房间,有n-1条通道连接这n个房间(每两个房间之间有且只有一条路,所以实际上就是一棵树),在每个房间中,有三种选择要么被杀则回到第一个房间,概率为ki,要么从出口逃离概率为ei,要么通过通道到达其他的房间。

    解题思路:

    好题。

    状态转移方程很好想,但是求的时候有技巧,不能直接用高斯消元来求(n有10000)肯定会超时。发现知,此题是在一棵树上转移,所以可以借助树的特点,分成两部分儿子和父亲,抽象出系数,然后从叶子节点向上求出父亲节点。

    以下文字选自http://blog.csdn.net/morgan_xww/article/details/6776947

    设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
        
        叶子结点:
        E[i] = ki*E[1] + ei*0 + (1-ki-ei)*(E[father[i]] + 1);
             = ki*E[1] + (1-ki-ei)*E[father[i]] + (1-ki-ei);
        
        非叶子结点:(m为与结点相连的边数)
        E[i] = ki*E[1] + ei*0 + (1-ki-ei)/m*( E[father[i]]+1 + ∑( E[child[i]]+1 ) );
             = ki*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei)/m*∑(E[child[i]]) + (1-ki-ei);
        
        设对每个结点:E[i] = Ai*E[1] + Bi*E[father[i]] + Ci;
        
        对于非叶子结点i,设j为i的孩子结点,则
        ∑(E[child[i]]) = ∑E[j]
                       = ∑(Aj*E[1] + Bj*E[father[j]] + Cj)
                       = ∑(Aj*E[1] + Bj*E[i] + Cj)
        带入上面的式子得
        (1 - (1-ki-ei)/m*∑Bj)*E[i] = (ki+(1-ki-ei)/m*∑Aj)*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei) + (1-ki-ei)/m*∑Cj;
        由此可得
        Ai =        (ki+(1-ki-ei)/m*∑Aj)   / (1 - (1-ki-ei)/m*∑Bj);
        Bi =        (1-ki-ei)/m            / (1 - (1-ki-ei)/m*∑Bj);
        Ci = ( (1-ki-ei)+(1-ki-ei)/m*∑Cj ) / (1 - (1-ki-ei)/m*∑Bj);
        
        对于叶子结点
        Ai = ki;
        Bi = 1 - ki - ei;
        Ci = 1 - ki - ei;
        
        从叶子结点开始,直到算出 A1,B1,C1;
        
        E[1] = A1*E[1] + B1*0 + C1;
        所以
        E[1] = C1 / (1 - A1);
        若 A1趋近于1则无解...

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #define eps 1e-9
    #define INF 0x3fffffff
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 10100
    
    int deg[Maxn],cnt,n;
    double A[Maxn],B[Maxn],C[Maxn]; //分别表示系数
    double k[Maxn],e[Maxn];//表示被杀和逃离概率
    
    struct Edge
    {
        int v;
        struct Edge * next;
    }edge[Maxn<<1],*head[Maxn<<1];
    
    void add(int a,int b)
    {
        ++cnt;
        deg[a]++; //度数
        edge[cnt].v=b,edge[cnt].next=head[a];
        head[a]=&edge[cnt];
    }
    void dfs(int cur,int pre)
    {
        struct Edge * p=head[cur];
        bool flag=true;
        double suma=0,sumb=0,sumc=0;
    
        while(p)
        {
            int v=p->v;
            if(v!=pre)
            {
                flag=false;  //不是叶子节点
                dfs(v,cur);suma+=A[v];sumb+=B[v];sumc+=C[v];
            } //求出儿子节点的各和
            p=p->next;
        }
        if(flag) //叶子节点
        {
            double t=1-k[cur]-e[cur];
            A[cur]=k[cur],B[cur]=t,C[cur]=t;
            return ;
        }//非叶子节点
        double temp=(1-k[cur]-e[cur])/deg[cur];
        double tt=1-temp*sumb;
    
        A[cur]=(k[cur]+temp*suma)/tt;
        B[cur]=temp/tt;
        C[cur]=(temp*sumc+(1-k[cur]-e[cur]))/tt;
        return ;
    }
    
    int main()
    {
        int t;
    
        scanf("%d",&t);
        for(int ca=1;ca<=t;ca++)
        {
            scanf("%d",&n);
            memset(head,NULL,sizeof(head));
            memset(deg,0,sizeof(deg));
            cnt=0;
    
            for(int i=1;i<n;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                add(a,b),add(b,a);
            }
            for(int i=1;i<=n;i++)
            {
                double a,b;
                scanf("%lf%lf",&a,&b);
                k[i]=a/100.0,e[i]=b/100.0;
            }
            dfs(1,-1);
            printf("Case %d: ",ca);
            if(fabs(1-A[1])<eps) //这里卡精度
                printf("impossible
    ");
            else
                printf("%.5f
    ",C[1]/(1.0-A[1]));
        }
       return 0;
    }
    
    




  • 相关阅读:
    埃拉托色尼的素数查找法的优化问题
    Salesforce开发者学习笔记之三:Salesforce平台架构
    Salesforce开发者学习笔记之二:Salesforce开发平台应用场景
    Salesforce开发者学习笔记之一:基本知识
    Salesforce Apex 使用JSON数据的示例程序
    Salesforce Apex页面中调用远端网络服务
    Salesforce Apex 开发环境设置和Hello World示例
    四、Java 安装
    三、Windows 基础
    二、大数据生态圈尝鲜
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3315532.html
Copyright © 2011-2022 走看看