期望DP——HDU4035Maze

Description

HDU传送门

题目简述:

你被困在一个迷宫里面,这个迷宫是一颗树,每一个结点都有一个出口,且第\(i\)结点都有三种可能:

  1. \(k_i\)的概率被杀死,杀死后你会回到1号结点
  2. \(e_i\)的概率逃脱
  3. \(1-k_i-e_i\)的概率从与\(i\)相邻的\(m\)条边出去(所以走与\(i\)相邻一条边的概率是\(\frac {1-k_i-e_i}{m}\)

求逃出迷宫的期望步数。

Solution

假设\(dp_i\)表示从第\(i\)个结点出发逃脱的期望步数,\(f_i\)\(i\)号结点的父亲结点,\(son_i\)\(i\)号结点的儿子结点,那么有:

\[\begin{cases} i点非叶子结点时:\\ dp_i=k_i*dp_1+e_i*0+\frac{1-k_i-e_i}{m}*(dp_{f_i}+1+\sum (dp_{son_i}+1) )\\ =k_i*dp_1+\frac {1-k_i-e_i}{m}*dp_{f_i}+\frac {1-k_i-e_i}{m}*\sum dp_{son_i}+1-k_i-e_i\\ i点为叶子结点时:\\ dp_i=k_i*dp_1+(1-k_i-e_i)*(dp_{f_i}+1)\\ =k_i*dp_1+(1-k_i-e_i)*dp_{f_i}+1-k_i-e_i \end{cases} \]

发现可以把它们设置成统一形式:\(dp_i=A_i*dp_1+B_i*dp_{f_i}+C_i\)

对于非叶子结点\(i\),设它的儿子为\(j\)

\(\sum dp_{son_i}=\sum (A_j*dp_1+B_j*dp_i+C_j)\\dp_i=A_i*dp_1+B_i*dp_{f_i}+\frac {1-k_i-e_i}{m}*\sum(A_{son_i}*dp_1+B_{son_i}*dp_i+C_{son_i})+1-k_i-e_i\\=(A_i+(\sum A_{son_i})*\frac {1-k_i-e_i}{m})*dp_1+B_i*dp_{f_i}+\frac {1-k_i-e_i}{m}*(\sum B_{son_i})*dp_i+\frac {1-k_i-e_i}{m}*\sum C_{son_i}+1-k_i-e_i\\\therefore (1-\frac {1-k_i-e_i}{m}*\sum B{son_i})*dp_i=(k_i+(\sum A_{son_i})*\frac {1-k_i-e_i}{m})*dp_1+\frac {1-k_i-e_i}{m}*dp_{f_i}+\frac {1-k_i-e_i}{m}*\sum C_{son_i}+1-k_i-e_i\\\)

这样下来,\(dp_i\)\(A_i,B_i,C_i\)都只与儿子结点有关了,就可以从下往上计算,最终答案就是\(dp_1\)

注意:如果有一个结点的逃脱期望步数是0,那么无解,因为有可能一直在循环。

Code

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
#define sz(x) (int)x.size()
using namespace std;
const int N=1e4+5;
int T,n,du[N];
double p[N][3],A[N],B[N],C[N];
vector<int> e[N];

inline int read () {
    int res=0,fl=1;
    char ch;
    while ((ch=getchar())&&(ch<'0'||ch>'9')) if (ch=='-') fl=-1;
    res=ch^48;
    while ((ch=getchar())&&ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48);
    return res*fl;
}

inline bool dfs (int x,int fa) {//cout<<x<<endl;
    int son=du[x];
    A[x]=p[x][0];
    B[x]=p[x][2]/son;
    C[x]=p[x][2];
    double tmp=0;
    for (int i=0;i<sz(e[x]);i++) {
        int v=e[x][i];
        if (v==fa) continue;
        if (!dfs(v,x)) return false;
        A[x]+=p[x][2]/son*A[v];
        C[x]+=p[x][2]/son*C[v];
        tmp+=p[x][2]/son*B[v];
    }
    if (fabs(1-tmp)<1e-9) return false;
    A[x]/=1-tmp;
    B[x]/=1-tmp;
    C[x]/=1-tmp;
    return true;
}

inline void clean () {
    memset(A,0,sizeof(A));
    memset(B,0,sizeof(B));
    memset(C,0,sizeof(C));
    memset(du,0,sizeof(du));
    for (int i=1;i<=n;i++) e[i].clear();
}

int main () {
//    freopen("4035.in","r",stdin);
//    freopen("4035.out","w",stdout);
    T=read();
    for (int t=1;t<=T;t++) {
        n=read();
        clean();
        for (int i=1;i<n;i++) {
            int u=read(),v=read();du[u]++;du[v]++;
            e[u].push_back(v);e[v].push_back(u);
        }
        for (int i=1;i<=n;i++) p[i][0]=read()/100.0,p[i][1]=read()/100.0;
        for (int i=1;i<=n;i++) p[i][2]=1-p[i][0]-p[i][1];
//        cout<<p[1][0]<<endl;
        printf("Case %d: ",t);
        if (dfs(1,1)&&fabs(1-A[1])>1e-9) printf("%.6lf\n",C[1]/(1-A[1]));
        else puts("impossible");
    }
    return 0;
}
posted @ 2020-11-22 19:44  蒟蒻zyx_qwq  阅读(80)  评论(0编辑  收藏  举报