期望DP——HDU4035Maze
Description
题目简述:
你被困在一个迷宫里面,这个迷宫是一颗树,每一个结点都有一个出口,且第\(i\)结点都有三种可能:
- 有\(k_i\)的概率被杀死,杀死后你会回到1号结点
- 有\(e_i\)的概率逃脱
- 有\(1-k_i-e_i\)的概率从与\(i\)相邻的\(m\)条边出去(所以走与\(i\)相邻一条边的概率是\(\frac {1-k_i-e_i}{m}\))
求逃出迷宫的期望步数。
Solution
假设\(dp_i\)表示从第\(i\)个结点出发逃脱的期望步数,\(f_i\)为\(i\)号结点的父亲结点,\(son_i\)为\(i\)号结点的儿子结点,那么有:
发现可以把它们设置成统一形式:\(dp_i=A_i*dp_1+B_i*dp_{f_i}+C_i\)。
对于非叶子结点\(i\),设它的儿子为\(j\):
\(\sum dp_{son_i}=\sum (A_j*dp_1+B_j*dp_i+C_j)\\dp_i=A_i*dp_1+B_i*dp_{f_i}+\frac {1-k_i-e_i}{m}*\sum(A_{son_i}*dp_1+B_{son_i}*dp_i+C_{son_i})+1-k_i-e_i\\=(A_i+(\sum A_{son_i})*\frac {1-k_i-e_i}{m})*dp_1+B_i*dp_{f_i}+\frac {1-k_i-e_i}{m}*(\sum B_{son_i})*dp_i+\frac {1-k_i-e_i}{m}*\sum C_{son_i}+1-k_i-e_i\\\therefore (1-\frac {1-k_i-e_i}{m}*\sum B{son_i})*dp_i=(k_i+(\sum A_{son_i})*\frac {1-k_i-e_i}{m})*dp_1+\frac {1-k_i-e_i}{m}*dp_{f_i}+\frac {1-k_i-e_i}{m}*\sum C_{son_i}+1-k_i-e_i\\\)
这样下来,\(dp_i\)的\(A_i,B_i,C_i\)都只与儿子结点有关了,就可以从下往上计算,最终答案就是\(dp_1\)。
注意:如果有一个结点的逃脱期望步数是0,那么无解,因为有可能一直在循环。
Code
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
#define sz(x) (int)x.size()
using namespace std;
const int N=1e4+5;
int T,n,du[N];
double p[N][3],A[N],B[N],C[N];
vector<int> e[N];
inline int read () {
int res=0,fl=1;
char ch;
while ((ch=getchar())&&(ch<'0'||ch>'9')) if (ch=='-') fl=-1;
res=ch^48;
while ((ch=getchar())&&ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48);
return res*fl;
}
inline bool dfs (int x,int fa) {//cout<<x<<endl;
int son=du[x];
A[x]=p[x][0];
B[x]=p[x][2]/son;
C[x]=p[x][2];
double tmp=0;
for (int i=0;i<sz(e[x]);i++) {
int v=e[x][i];
if (v==fa) continue;
if (!dfs(v,x)) return false;
A[x]+=p[x][2]/son*A[v];
C[x]+=p[x][2]/son*C[v];
tmp+=p[x][2]/son*B[v];
}
if (fabs(1-tmp)<1e-9) return false;
A[x]/=1-tmp;
B[x]/=1-tmp;
C[x]/=1-tmp;
return true;
}
inline void clean () {
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
memset(C,0,sizeof(C));
memset(du,0,sizeof(du));
for (int i=1;i<=n;i++) e[i].clear();
}
int main () {
// freopen("4035.in","r",stdin);
// freopen("4035.out","w",stdout);
T=read();
for (int t=1;t<=T;t++) {
n=read();
clean();
for (int i=1;i<n;i++) {
int u=read(),v=read();du[u]++;du[v]++;
e[u].push_back(v);e[v].push_back(u);
}
for (int i=1;i<=n;i++) p[i][0]=read()/100.0,p[i][1]=read()/100.0;
for (int i=1;i<=n;i++) p[i][2]=1-p[i][0]-p[i][1];
// cout<<p[1][0]<<endl;
printf("Case %d: ",t);
if (dfs(1,1)&&fabs(1-A[1])>1e-9) printf("%.6lf\n",C[1]/(1-A[1]));
else puts("impossible");
}
return 0;
}