HDU 4035 Maze 概率dp,树形dp 难度:2
http://acm.hdu.edu.cn/showproblem.php?pid=4035
求步数期望,设E[i]为在编号为i的节点时还需要走的步数,father为dfs树中该节点的父节点,son为dfs树种该节点的子节点的集合,kl[i]为被杀掉的概率,ex[i]为逃出的概率
mv[i]=(1-kl[i]-ex[i])/(1+len(son))
则明显
E[i]=(E[father]+1)*mv[i]+sigma((E[son]+1)*mv[i])+E[1]*K[i]
未知量是E[i],E[father],E[1]
对于叶节点,设E0[i]为该公式中E[1]的系数,EE[i]为该公式中的常数项,EF[i]为E[father]的系数,则可以用这三个值表示E[i]
对于非叶节点,从E[son]中可以得到son的E0,EE,EF,另设ES[i]为E[i]在儿子中积累的系数,则
EF[i]:mv[i]
ES[i]:(由儿子积累来的)sigma(EF[son]*mv[i])
EE[i]:1-kl[i]-ex[i]+sigma(EE[son]*mv[i])
E0[i]:kl[i]+sigma(E0[son]*mv[i])
计算完了之后再EE,E0,EF都除以(1-ES[i]),ES[i]为1当然就不能走出这个迷宫了
这样到了1这个节点就是E[1]=EE[1]/(1-ES[1]-E0[1])
一开始以为exit时应该有E[i]=ex[i]*E[i]+(E[father]+1)*mv[i]+sigma((E[son]+1)*mv[i])+E[1]*K[i],这里思想卡住了,实际上应该是ex[i]*0
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int maxn = 1e4+4; const double eps = 1e-10; int n; double kl[maxn],ex[maxn],mv[maxn];//kill exit move int first[maxn],deg[maxn]; int dcmp(double a,double b){ if(fabs(a-b)<eps)return 0; return a>b?1:-1; } struct edge{ int f,t,nxt; }e[maxn*2]; void addedge(int f,int t,int ind){ e[ind].nxt=first[f]; e[ind].t=t; e[ind].f=f; first[f]=ind; } void input(){ memset(first,-1,sizeof first); memset(deg,0,sizeof deg); scanf("%d",&n); for(int i=1;i<n;i++){ int f,t; scanf("%d%d",&f,&t); addedge(f,t,2*i); addedge(t,f,2*i+1); deg[f]++; deg[t]++; } for(int i=1;i<=n;i++){ scanf("%lf%lf",kl+i,ex+i); kl[i]/=100;ex[i]/=100; if(deg[i])mv[i]=(1-ex[i]-kl[i])/deg[i]; } } double ef[maxn],es[maxn],e0[maxn],ee[maxn]; bool dfs(int s,int father){ ef[s]=mv[s]; //es[s]=ex[s]; e0[s]=kl[s]; ee[s]=1-kl[s]-ex[s]; for(int p=first[s];p!=-1;p=e[p].nxt){ int t=e[p].t; if(t==father)continue; if(!dfs(t,s))return false; es[s]+=ef[t]*mv[s]; e0[s]+=e0[t]*mv[s]; ee[s]+=ee[t]*mv[s]; } if(dcmp(es[s],1)!=0&&s!=1){ e0[s]/=(1-es[s]); ef[s]/=(1-es[s]); ee[s]/=(1-es[s]); } return true; } double calc(){ memset(ee,0,sizeof ee); memset(ef,0,sizeof ef); memset(es,0,sizeof es); memset(e0,0,sizeof e0); if(!dfs(1,-1)||dcmp(e0[1]+es[1],1)==0)return -1; return ee[1]/(1-e0[1]-es[1]); } int main(){ int T; scanf("%d",&T); for(int ti=1;ti<=T;ti++){ input(); double ans=calc(); if(ans>-eps) printf("Case %d: %.6f\n",ti,ans); else printf("Case %d: impossible\n",ti); } return 0; }