hdu 4035 Maze 概率DP
题意:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。
思路:
设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
叶子结点:有3种情况:kill ;exit(成功出去的期望为0) ;回到父节点。
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则无解...
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4035
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<iomanip> 5 #include<cmath> 6 #include<cstring> 7 #include<vector> 8 #define ll __int64 9 #define pi acos(-1.0) 10 #define MAX 10005 11 using namespace std; 12 vector<int>p[MAX]; 13 double A[MAX],B[MAX],C[MAX],k[MAX],e[MAX]; 14 bool dfs(int n,int f) 15 { 16 int m=p[n].size(); 17 double d=1-k[n]-e[n]; 18 A[n]=k[n]; 19 B[n]=d/m; 20 C[n]=d; 21 if(m==1&&f!=-1) return true; 22 double temp=0.0; 23 for(int i=0;i<m;i++){ 24 int v=p[n][i]; 25 if(v==f) continue; 26 if(!dfs(v,n)) return false; 27 A[n]+=B[n]*A[v]; 28 C[n]+=B[n]*C[v]; 29 temp+=B[n]*B[v]; 30 } 31 temp=1-temp; 32 if(temp<=1e-9) return false; 33 A[n]/=temp; 34 B[n]/=temp; 35 C[n]/=temp; 36 return true; 37 } 38 int main(){ 39 int t,i,n,a,b,c=0; 40 scanf("%d",&t); 41 while(t--){ 42 scanf("%d",&n); 43 for(i=1;i<=n;i++) p[i].clear(); 44 for(i=1;i<n;i++){ 45 scanf("%d%d",&a,&b); 46 p[a].push_back(b); 47 p[b].push_back(a); 48 } 49 for(i=1;i<=n;i++){ 50 scanf("%lf%lf",&k[i],&e[i]); 51 k[i]/=100.0; 52 e[i]/=100.0; 53 } 54 printf("Case %d: ",++c); 55 if(dfs(1,-1)&&fabs(1-A[1])>1e-9) 56 printf("%.6lf\n",C[1]/(1-A[1])); 57 else printf("impossible\n"); 58 } 59 return 0; 60 }