Maze HDU

来源:互联网 发布:discuz 附件 阿里云 编辑:程序博客网 时间:2024/06/15 05:58

题意:

一道过程很有趣的概率dp

在一棵树上

你在节点1(根节点),

每个节点有一定概率k[i]被杀回到1号根节点,和一定概率e[i]逃离迷宫

还有剩下的概率往下一步走可以走向相邻的任何节点

问离开迷宫走的步数的期望是多少?

思路:

这个题目和 ZOJ 3329 One Person Game(概率DP,求期望)一样

每一部都是可以通过一定概率回到第一步的

即每一步的期望都有根节点期望的一部分


E[i]  =  ki * E[1]  + (1/m) *p[i]*(  (E[father]+1) + sigma(E[son]+1) )  m为度数,p[i]=1-ki-ei,每次走一步+1,

E[i]  =  ki * E[1]  + (1/m) *p[i]*(  E[father] + sigma E[son]   )   +p[i]


按照套路 我们定义  E[i]  =  A[i] *E[1] + B[i]*E[father] +C[i];

带入E[son]

E[i]  =  ki * E[1]  + (1/m) *p[i]*(  E[father] + sigma ( A[soni] *E[1] + B[soni]*E[i] +C[soni])   )   +p[i]

(1  -  p[i]/m*sigmaB[ison])E[i] =( k[i]+p[i]/m*sigma A[soni] )E[1] + (P[i]/m)*E[father] + (P[i]/m)* sigmaC[i] +p[i]

得出递推公式

A[i] = ( k[i]+p[i]/m*sigma A[soni] ) / (1  -  p[i]/m*sigmaB[ison])

B[i] =                               (P[i]/m)  /  (1  -  p[i]/m*sigmaB[ison])

C[i]=((P[i]/m)* sigmaC[i] +p[i] ) / (1  -  p[i]/m*sigmaB[ison])


 E[1]  =  A[1] *E[1]  +C[1];

 E[1]  =C[1]/(1-A[1])


#include<bits/stdc++.h>#define N 10009const double eps=1e-9;  using namespace std;vector<int> son[N];double p[N],k[N];double A[N],B[N],C[N];//A[i]=ki + pi/m *(sum A[son])//B[i]=pi/m//C[i]=pi/m sum(c[son]) +pi//D = 1/(1-pi/m*sum[son])bool dfs(int rt,int fa){double m=son[rt].size();A[rt]=k[rt];B[rt]=p[rt]/m;C[rt]=p[rt];double D=0;m=p[rt]/m;for(int i=0;i<son[rt].size();i++){if(son[rt][i]==fa) continue; if(!dfs(son[rt][i],rt)) return false;A[rt]+=(m*A[son[rt][i]]);C[rt]+=(m*C[son[rt][i]]);D+=(m*B[son[rt][i]]);}if(fabs(1.0-D)<eps) return false;A[rt]/=(1.0-D);B[rt]/=(1.0-D);C[rt]/=(1.0-D);return true;}int main(){int a,b,t,n;cin>>t;int kk=1;while(t--){cin>>n;for(int i=1;i<=n;i++)son[i].clear();for(int i=1;i<n;i++){scanf("%d%d",&a,&b);son[a].push_back(b);son[b].push_back(a);}for(int i=1;i<=n;i++){scanf("%lf%lf",k+i,p+i);k[i]/=100.0;p[i]/=100.0;p[i]=1.0- k[i]  -p[i];}if(dfs(1,-1)&&fabs(A[1]-1.0)>eps){double ans=C[1]/(1.0-A[1]);printf("Case %d: %.6lf\n",kk++,ans);}else    printf("Case %d: impossible\n",kk++);}return 0;}