题目大意:在一个树形迷宫中,以房间为节点。有n间房间,每间房间存在陷阱的概率为ki,存在出口的概率为ei,如果这两种情况都不存在(概率为pi),那么只能做出选择走向下一个房间(包括可能会走向上一个房间)。根节点为1,当遇到陷阱时必须返回到根节点1处重新开始,当遇到出口时,走出迷宫。问从开始到走出迷宫所做出选择次数的期望值。
题目分析:定义状态dp(i)表示在节点 i 处直到走出迷宫的选择次数期望值。则状态转移方程为:
dp(i)=ki*dp(1)+(1/m)*pi*∑(dp(son)+1) (i为叶子节点) <1>
dp(i)=ki*dp(1)+(1/m)*pi*(dp(father)+1)+(1/m)*pi*∑(dp(son)+1) (i为非叶子节点) <2>
将<2>整理一下,得到:
dp(i)=ki*dp(1)+(1/m)*pi*dp(father)+(1/m)*pi*∑dp(son)+pi
显然,dp(i)都与dp(1)有关,另dp(i)=A(i)*dp(1)+B(i)*dp(father)+C(i) <3>
将<3>带入∑dp(son),得到:
(1-(pi/m)*∑A(son))dp(i)=(ki+(pi/m)∑A(son))*dp(1)+(pi/m)*dp(father)+(pi/m)*∑C(son)+pi
显然,A(i),B(i),C(i)可得。
dp(1)=C(1)/(1-A(1)) 即为答案。
代码如下:
# include<iostream> # include<cstdio> # include<cmath> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int N=10005; const int INF=100000; const double eps=1e-9; int n; double k[N]; double e[N]; double A[N],B[N],C[N]; vector<int>G[N]; bool dfs(int u,int fa) { int m=G[u].size(); double temp=0; A[u]=k[u]; B[u]=(1-k[u]-e[u])/m; C[u]=1-k[u]-e[u]; for(int i=0;i<m;++i){ int v=G[u][i]; if(v==fa) continue; if(!dfs(v,u)) return false; A[u]+=(1-k[u]-e[u])*A[v]/m; C[u]+=(1-k[u]-e[u])*C[v]/m; temp+=(1-k[u]-e[u])*B[v]/m; } if(fabs(1-temp)<eps) return false; A[u]/=(1-temp); B[u]/=(1-temp); C[u]/=(1-temp); return true; } int main() { int T,x,y,cas=0; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;++i) G[i].clear(); for(int i=1;i<n;++i){ scanf("%d%d",&x,&y); G[x].push_back(y); G[y].push_back(x); } for(int i=1;i<=n;++i){ scanf("%lf%lf",k+i,e+i); k[i]/=100; e[i]/=100; } printf("Case %d: ",++cas); if(dfs(1,-1)&&fabs(1-A[1])>eps) printf("%.6lf\n",C[1]/(1-A[1])); else printf("impossible\n"); } return 0; }
时间: 2024-10-27 19:11:49