http://acm.hdu.edu.cn/showproblem.php?pid=4035
题意:给一个树状的迷宫,某个人一开始在第1个点,他想逃出这个迷宫,若他在第i个点,他有e[i]%的机会逃出迷宫,k[i]%被杀(若他被杀,则回到第一个点),或者等概率地走向一个相邻的点(这个人毫无记忆力),问这个人走出这个迷宫要经过的边数的期望值。
思路:以1号点为根建树,f[i]表示人在第i个点走出去的边数的期望值,则f[i] = e[i] + k[i]*f[1] + sigma((1-e[i]-k[i])/(ns+1)*(f[s]+1)) + (1-e[i]-k[i])/(ns+1)*(f[a]+1) // s为i的儿子,a为父亲,把式子化简,结合树dp的思想,各个点f[i]都可以归结为f[i] = A[i] + B[i]*f[1] + C[i]*f[a],儿子直接合并到父亲,从下往上dp到最后的结果是f[1] = A[1] + B[i] * f[1], 解一元一次方程即可。
程序:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 10010
#define eps (1e-9)
#define INF 1000000000
#define sqr(x) ((x) * (x))
#define two(x) (1 << (x))
#define X first
#define Y second
typedef long long LL;
int n, ne;
int head[MAXN], k[MAXN], e[MAXN], ns[MAXN];
double A[MAXN], B[MAXN], C[MAXN];
pair<int, int> edge[MAXN * 2];
bool flag[MAXN];
void add_edge(int x, int y)
{
++ne;
edge[ne] = make_pair(y, head[x]);
head[x] = ne;
}
void init()
{
ne = 0;
memset(head, -1, sizeof(head));
scanf("%d", &n);
for (int i = 1; i < n; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
add_edge(x, y);
add_edge(y, x);
}
for (int i = 1; i <= n; ++i) scanf("%d%d", &k[i], &e[i]);
}
void dfs(int x, int mark)
{
int pnt = head[x];
double ee = e[x] / 100.0, kk = k[x] / 100.0, u = (1 - ee - kk) / ns[x];
double v = 0;
if (mark == 0)
ns[x] = (x != 1);
else
{
A[x] = 1 - kk;
B[x] = kk;
C[x] = u * (x != 1);
}
while (pnt != -1)
{
int y = edge[pnt].X;
if (!flag[y])
{
flag[y] = true;
dfs(y, mark);
if (mark == 1)
{
A[x] += u * A[y];
B[x] += u * B[y];
v += u * C[y];
}
else
++ns[x];
}
pnt = edge[pnt].Y;
}
if (mark == 1)
{
A[x] /= (1 - v);
B[x] /= (1 - v);
C[x] /= (1 - v);
}
}
void work()
{
memset(flag, 0, sizeof(flag));
flag[1] = true;
dfs(1, 0);
memset(flag, 0, sizeof(flag));
flag[1] = true;
dfs(1, 1);
if (fabs(1 - B[1]) < eps) puts("impossible");
else printf("%.6lf\n", A[1] / (1 - B[1]) - 1);
}
int main()
{
int T, ca = 0;
scanf("%d", &T);
while (T--)
{
printf("Case %d: ", ++ca);
init();
work();
// for (int i = 1; i <= n; ++i) cout << A[i] << ' ' << B[i] << ' ' << C[i] << endl;
}
return 0;
}