題意:
一道過程很有趣的概率dp
在一棵樹上
你在節點1(根節點),
每個節點有一定概率k[i]被殺回到1號根節點,和一定概率e[i]逃離迷宮
還有剩下的概率往下一步走可以走向相鄰的任何節點
問離開迷宮走的步數的期望是多少?
思路:
這個題目和 ZOJ 3329 One Person Game(概率DP,求期望)一樣
每一部都是可以通過一定概率回到第一步的
即每一步的期望都有根節點期望的一部分
E[i] = ki * E[1] + (1/m) *p[i]*( (E[father]+1) + sigma(E[son]+1) ) m爲度數,p[i]=1-ki-ei,每次走一步+1,
E[i] = ki * E[1] + (1/m) *p[i]*( E[father] + sigma E[son] ) +p[i]
按照套路 我們定義 E[i] = A[i] *E[1] + B[i]*E[father] +C[i];
帶入E[son]
E[i] = ki * E[1] + (1/m) *p[i]*( E[father] + sigma ( A[soni] *E[1] + B[soni]*E[i] +C[soni]) ) +p[i]
(1 - p[i]/m*sigmaB[ison])E[i] =( k[i]+p[i]/m*sigma A[soni] )E[1] + (P[i]/m)*E[father] + (P[i]/m)* sigmaC[i] +p[i]
得出遞推公式
A[i] = ( k[i]+p[i]/m*sigma A[soni] ) / (1 - p[i]/m*sigmaB[ison])
B[i] = (P[i]/m) / (1 - p[i]/m*sigmaB[ison])
C[i]=((P[i]/m)* sigmaC[i] +p[i] ) / (1 - p[i]/m*sigmaB[ison])
E[1]
= A[1] *E[1] +C[1];
E[1] =C[1]/(1-A[1])
#include<bits/stdc++.h>
#define N 10009
const double eps=1e-9;
using namespace std;
vector<int> son[N];
double p[N],k[N];
double A[N],B[N],C[N];
//A[i]=ki + pi/m *(sum A[son])
//B[i]=pi/m
//C[i]=pi/m sum(c[son]) +pi
//D = 1/(1-pi/m*sum[son])
bool dfs(int rt,int fa)
{
double m=son[rt].size();
A[rt]=k[rt];
B[rt]=p[rt]/m;
C[rt]=p[rt];
double D=0;
m=p[rt]/m;
for(int i=0;i<son[rt].size();i++)
{
if(son[rt][i]==fa) continue;
if(!dfs(son[rt][i],rt)) return false;
A[rt]+=(m*A[son[rt][i]]);
C[rt]+=(m*C[son[rt][i]]);
D+=(m*B[son[rt][i]]);
}
if(fabs(1.0-D)<eps) return false;
A[rt]/=(1.0-D);
B[rt]/=(1.0-D);
C[rt]/=(1.0-D);
return true;
}
int main()
{
int a,b,t,n;
cin>>t;
int kk=1;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
son[i].clear();
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
son[a].push_back(b);
son[b].push_back(a);
}
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",k+i,p+i);
k[i]/=100.0;
p[i]/=100.0;
p[i]=1.0- k[i] -p[i];
}
if(dfs(1,-1)&&fabs(A[1]-1.0)>eps)
{
double ans=C[1]/(1.0-A[1]);
printf("Case %d: %.6lf\n",kk++,ans);
}
else
printf("Case %d: impossible\n",kk++);
}
return 0;
}