【题意】:有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 

             从结点1出发,开始走,在每个结点i都有3种可能: 

              1.被杀死,回到结点1处(概率为ki) 

              2.找到出口,走出迷宫 (概率为ei) 

              3.和该点相连有m条边,随机走一条 

             求:走出迷宫所要走的边数的期望值。


【题解】:这是一道树dp求期望的题目。
             设E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
    
             叶子结点:
             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;
             由此可得
                对于非叶子结点,其中j为i的儿子结点
                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). 当(1 - A[1]) 趋近于0时,E[1] 趋近于∞,因此无解。

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "vector"
 5 #include "cmath"
 6 using namespace std;
 7 #define pb push_back
 8 #define maxn 10050
 9 #define eps 1e-10
10 vector<int> g[maxn];
11 double k[maxn], e[maxn], p[maxn];
12 double a[maxn], b[maxn], c[maxn];
13 int n;
14 
15 void dfs(int u, int fa) {
16     int size = g[u].size();
17     if(size == 1 && fa != -1) {
18         a[u] = k[u];
19         b[u] = c[u] = p[u];
20         return;
21     }
22     double aa = 0, bb = 0, cc = 0;
23     for(int i = 0; i < size; i++) {
24         int v = g[u][i];
25         if(v == fa) continue;
26         dfs(v, u);
27         aa += a[v], bb += b[v], cc += c[v];
28     }
29     double tmp = (1 - p[u] * bb / size);
30     a[u] = (k[u] + p[u] * aa / size) / tmp;
31     b[u] = (p[u] / size) / tmp;
32     c[u] = (p[u] + p[u] * cc / size) / tmp;
33     return;
34 }
35 
36 
37 int main() {
38     int T, Case = 1;
39     int u, v;
40     scanf("%d"&T);
41     while(T--) {
42         scanf("%d"&n);
43         for(int i = 0; i < maxn; i++) g[i].clear();
44         for(int i = 0; i < n - 1; i++) {
45             scanf("%d%d:"&u, &v);
46             g[u].pb(v);
47             g[v].pb(u);
48         }
49         for(int i = 1; i <= n; i++) {
50             scanf("%lf%lf"&k[i], &e[i]);
51             k[i] /= 100, e[i] /= 100;
52             p[i] = 1 - k[i] - e[i];
53         }
54         dfs(1-1);
55         printf("Case %d: ", Case++);
56         if(fabs(1 - a[1]) < eps) printf("impossible\n");
57         else {
58             double ans = c[1/ (1 - a[1]);
59             printf("%.6f\n", ans);
60         }
61     }
62     return 0;
63 }
64