HDU--4035(概率DP,公式推导与化简)

2015-04-24 19:33:18

题目:给你一棵树,一个人一开始从节点1(根)出发,等概率地选择相邻节点行走,每到一个节点 i 有 Ki 的概率被杀死,并回到节点1,有 Ei 的概率逃出这棵树。问这个人逃出这棵树要经过的期望路径数。

思路:这道题很好地体现了概率DP的特点:公式推导!一开始觉得这题很烦... 但是看了别人也没写得多难,于是果断开始推。

  我们定义 dp[i]为从节点 i 出发到逃出要经过的期望路径数。那么对于一个节点我们可以列出方程:

   ,m 表示节点 i 有 m 个相邻节点。

   发现 i 的每个儿子 ch[j] 的 dp[ch[j]] 都可以带入 dp[i] 中,将 dp[i] 的系数换元:

  (Aofch[j]表示 dp[ch[j]] 表达式中的 A)

  于是有: (A' = A / (1 - C))

  由上面式子可以发现,如果从节点1递归下去直到叶子节点,在回溯过程中把系数逐步计算出来,那么dp[1]也就很好计算了。

  显然:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=0;i<(n);++i)
17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
18 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
19 #define MP(a,b) make_pair(a,b)
20 #define PB(a) push_back(a)
21 
22 typedef long long ll;
23 typedef pair<int,int> pii;
24 const int INF = (1 << 30) - 1;
25 const int MAXN = 10010;
26 const double eps = 1e-9;
27 
28 int T,N,m[MAXN];
29 double dp[MAXN],K[MAXN],E[MAXN];
30 double A[MAXN],B[MAXN],C[MAXN],D[MAXN];
31 vector<int> g[MAXN];
32 
33 void Solve(int p,int pre){
34     //printf("p : %d\n",p);
35     A[p] = K[p];
36     B[p] = (1.0 - K[p] - E[p]) / m[p];
37     C[p] = 0.0;
38     D[p] = 1.0 - K[p] - E[p];
39     for(int i = 0; i < m[p]; ++i){
40         int v = g[p][i];
41         if(v == pre) continue;
42         Solve(v,p);
43         A[p] += B[p] * A[v];
44         D[p] += B[p] * D[v];
45         C[p] += B[p] * B[v];
46     }
47     A[p] /= (1.0 - C[p]);
48     B[p] /= (1.0 - C[p]);
49     D[p] /= (1.0 - C[p]);
50 }
51 
52 int main(){
53     int a,b;
54     scanf("%d",&T);
55     FOR(tt,1,T){
56         scanf("%d",&N);
57         FOR(i,1,N) g[i].clear();
58         REP(i,N - 1){
59             scanf("%d%d",&a,&b);
60             g[a].PB(b);
61             g[b].PB(a);
62         }
63         FOR(i,1,N) m[i] = g[i].size();
64         FOR(i,1,N){
65             scanf("%lf%lf",&K[i],&E[i]);
66             K[i] /= 100.0;
67             E[i] /= 100.0;
68         }
69         Solve(1,0);
70         printf("Case %d: ",tt);
71         if(fabs(1 - A[1]) < eps) printf("impossible\n");
72         else{
73             dp[1] = D[1] / (1 - A[1]);
74             printf("%.6f\n",dp[1]);
75         }
76     }
77     return 0;
78 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4454385.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值