有一个n个结点的树形迷宫,在每个结点有概率被杀,有概率逃出,否则随机选择一条边进入下一个结点,若被杀则回到结点一重新走迷宫,问逃出迷宫所走的边数期望
dp[i]为点i逃出的期望
和ZOJ - 3329类似dp方程中含有dp[1]而dp顺序是从叶节点到根节点1的,所以没法直接求
设
根据这两题来看,dp方程的设法应该是把还未求得的变量前乘上一个系数,然后已求得的变量合并为一个系数
最后就是解出A[i],B[i]和C[i]的递推式
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int mx = 10005;
vector <int> mat[mx];
int k[mx], e[mx];
bool vis[mx];
double A[mx], B[mx], C[mx];
int n;
double p(int x) {
return x/100.0;
}
bool judge(int u) {
vis[u] = true;
if (e[u] > 0) return true;
int len = mat[u].size();
for (int i = 0; i < len; i++) {
int v = mat[u][i];
if (vis[v]) continue;
if (k[v] < 100 && judge(v)) return true;
}
return false;
}
void dfs(int u) {
vis[u] = true;
double sum_A = 0, sum_B = 0, sum_C = 0;
int len = mat[u].size();
if (len == 1 && u != 1) {
A[u] = p(k[u]);
B[u] = (1.0-p(k[u])-p(e[u]));
C[u] = (1.0-p(k[u])-p(e[u]));
return ;
}
for (int i = 0; i < len; i++) {
int v = mat[u][i];
if (vis[v]) continue;
dfs(v);
sum_A += A[v]; sum_B += B[v]; sum_C += C[v];
}
A[u] = (p(k[u]) + (1.0-p(k[u])-p(e[u]))*sum_A/len) / (1.0-sum_B*(1.0-p(k[u])-p(e[u]))/len);
B[u] = (1.0-p(k[u])-p(e[u])) / len / (1.0-sum_B*(1.0-p(k[u])-p(e[u]))/len);
C[u] = (1.0-p(k[u])-p(e[u])) / len * (sum_C + len) / (1.0-sum_B*(1.0-p(k[u])-p(e[u]))/len);
return ;
}
void init() {
memset(vis, false, sizeof(vis));
for (int i = 0; i < mx; i++) {
A[i] = B[i] = C[i] = 0;
mat[i].clear();
}
}
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
init();
scanf("%d", &n);
int u, v;
for (int i = 1; i <= n-1; i++) {
scanf("%d%d", &u, &v);
mat[u].push_back(v);
mat[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
scanf("%d%d", &k[i], &e[i]);
}
printf("Case %d: ", ++kase);
if (!judge(1)) {
puts("impossible");
continue;
}
memset(vis, false, sizeof(vis));
dfs(1);
double ans = C[1] / (1-A[1]);
printf("%.9f\n", ans);
}
return 0;
}