第一次做概率DP,找了篇大神的借鉴一下
个人感觉,根据题意,每个数据节点均要父节点与子节点的数据联合计算,因此可以将问题化简为系数表达式
#include <CSTDIO>
#include <STRING.H>
#include <MATH.H>
#include <VECTOR>
using namespace std;
// hdu 4035
/*
概率dp求期望
e[i]表示从i走出迷宫需要的边数期望
叶子节点:
e[i] = bk[i]*e[1] + fd[i]*0 + (1-bk-fd)*(1+e[mother[i]]);
非叶子节点:
e[i] = bk[i]*e[1] + fd[i]*0 + (1-bk-fd)/m*(1+e[mother[i]]+Σ(e[child[i]]));
*/
const int MAXN = 10005;
const double _inf = 1e-10;
int n;
vector<int> mp[MAXN];
double bk[MAXN], fd[MAXN], mother[MAXN];
double A[MAXN], B[MAXN], C[MAXN];
bool dfs(int i, int mo)
{
if (mp[i].size() == 1 && mo) // 叶子节点&非节点1
{
A[i] = bk[i];
B[i] = 1 - bk[i] - fd[i];
C[i] = 1 - bk[i] - fd[i];
return true;
}
// 节点1 或 非叶子节点
A[i] = bk[i];
B[i] = (1 - bk[i] - fd[i])/mp[i].size();
C[i] = 1 - bk[i] - fd[i];
double tmp = 0.0;
for (int j = 0; j< mp[i].size(); ++j)
{
if ( mp[i][j] == mo ) continue;
if (!dfs(mp[i][j], i)) return false;
A[i] += A[mp[i][j]] * B[i];
C[i] += C[mp[i][j]] * B[i];
tmp += B[mp[i][j]] * B[i];
}
if (fabs(1-tmp) < _inf) return false;
A[i] /= 1 - tmp;
B[i] /= 1 - tmp;
C[i] /= 1 - tmp;
return true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int t, cs = 0;
int i, j, k;
scanf("%d", &t);
while (t--)
{
printf("Case %d: ", ++cs);
scanf("%d", &n);
for (i = 1; i<= n; ++i) mp[i].clear();
for (i = 1; i< n; ++i) scanf("%d%d", &j, &k),
mp[j].push_back(k), mp[k].push_back(j);
for ( i = 1; i<= n; ++i)
{
scanf("%lf%lf", &bk[i], &fd[i]);
bk[i] /= 100.0;
fd[i] /= 100.0;
}
if (dfs(1, 0) && fabs(1-A[1]) > _inf)
printf("%lf\n", C[1]/(1-A[1]));
else
printf("impossible\n");
}
return 0;
}