神一般的概率DP
基本的状态转移方程:
dp[i] = k[i]*dp[1] + e[i]*0 + (1-k[i]-e[i])/d[i]* ( ∑( dp[j]+1 ); (i, j相连)
把原图看成一棵树,可以把每一项的状态转移方程化简成只与其父节点有关。
然后写出来的话会比较复杂= =
我说的可能不够清楚,详见kuangbin大神的http://www.cnblogs.com/kuangbin/archive/2012/10/03/2711108.html
怒贴源代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <algorithm>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define fr first
#define sc second
#define mp make_pair
#define FOR(i,j,k) for(int i=j;i<=(k);i++)
#define FORD(i,j,k) for(int i=j;i>=(k);i--)
#define REP(i,n) for(int i=0;i<(n);i++)
const double eps = 1e-9;
const int maxn = 10005;
int T, cas = 1, n;
double k[maxn], e[maxn];
double dp[maxn], a[maxn], b[maxn], c[maxn];
vector<int> g[maxn];
bool dfs(int u, int fa)
{
double sa = 0, sb = 0, sc = 0;
for (int i=0;i<g[u].size();i++)
{
int v = g[u][i];
if (v == fa) continue;
if (!dfs(v, u)) return 0;
sa += a[v]; sb += b[v]; sc += c[v];
}
sa *= (1-k[u]-e[u]) / g[u].size();
sb *= (1-k[u]-e[u]) / g[u].size();
sc *= (1-k[u]-e[u]) / g[u].size();
if (fabs(sb - 1) < eps) return 0;
a[u] = (k[u] + sa) / (1 - sb);
b[u] = (1-k[u]-e[u]) / g[u].size() / (1 - sb);
c[u] = (1-k[u]-e[u] + sc) / (1 - sb);
return 1;
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
for (int i=0;i<=n;i++) g[i].clear();
for (int i=1,u,v;i<n;i++)
{
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
for (int i=1;i<=n;i++)
{
scanf("%lf%lf", &k[i], &e[i]);
k[i] /= 100; e[i] /= 100;
}
printf("Case %d: ", cas++);
if (!dfs(1, 0) || fabs(a[1] - 1) < eps) puts("impossible");
else printf("%.6lf\n", c[1] / (1 - a[1]));
}
return 0;
}