列方程,系数替换化简,递推求解
参考:http://www.cnblogs.com/kuangbin/archive/2012/10/03/2711108.html
/* HDU 4035 dp求期望的题。 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点1处(概率为ki) 2.找到出口,走出迷宫 (概率为ei) 3.和该点相连有m条边,随机走一条 求:走出迷宫所要走的边数的期望值。 设 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; 由此可得 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则无解... */
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <bitset>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000000;
const int MOD = 1000000007;
const int MAXN = 11000;
const double eps = 1e-10;
double A[MAXN], B[MAXN], C[MAXN];
double k[MAXN], e[MAXN];
vector<int>adj[MAXN];
int n, m;
bool dfs(int u, int fa)
{
int m = adj[u].size();
double pp = 1 - k[u] - e[u];///中间变量可能损失精度
A[u] = k[u];
B[u] = pp / m;
C[u] = pp;
double tmp = 0;
REP(i, m)
{
int v = adj[u][i];
if (v == fa) continue;
if (!dfs(v, u)) return false;
A[u] += pp / m * A[v];
C[u] += pp / m * C[v];
tmp += pp / m * B[v];
}
if (fabs(1 - tmp) < eps)///判断
return false;
A[u] /= (1 - tmp);
B[u] /= (1 - tmp);
C[u] /= (1 - tmp);
return true;
}
int main()
{
int T;
int ncase = 1;
RI(T);
while (T--)
{
RI(n);
REP(i, n + 1) adj[i].clear();
REP(i, n - 1)
{
int u, v;
RII(u, v);
adj[u].push_back(v);
adj[v].push_back(u);
}
FE(i, 1, n)
{
scanf("%lf%lf", &k[i], &e[i]);
k[i] /= 100;
e[i] /= 100;
}
printf("Case %d: ", ncase++);
if (dfs(1, -1) && fabs(1 - A[1]) > eps)///判断
{
printf("%.6lf\n", C[1] / (1 - A[1]));
}
else printf("impossible\n");
}
return 0;
}