[经典好题]HDU4035 Maze 期望树形DP
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[经典好题]HDU4035 Maze 期望树形DP相关的知识,希望对你有一定的参考价值。
这是我当年要刷的一道,自己想死活想不出来,于是去网上颓题解,然后:
这特么怎么想都想不出来啊!
题意是这个样子滴:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。
题解(借鉴自别人QAQ):
设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
对于点i:
1,点i是叶子结点,则:
E(i)=ki*E(1)+ei*0+(1-ki-ei)*(E(father)+1)
=>E(i)=ki*E(1)+(1-ki-ei)*E(father)+(1-ki-ei)
2,点i非叶子结点,则:
E(i)=ki*E(1)+ei*0+(1-ki-ei)/m *(E(father)+1)+(1-ki-ei)/m*∑(E(child)+1)
=>E(i)=ki*E(1)+(1-ki-ei)/m *E(father)+(1-ki-ei)/m*∑(E(child))+(1-ki-ei);//作为1式
从公式可知求E(i)需要求到E(father),E(child)
但这是很难求到的,因为即使是叶子结点也需要知道E(1),但是E(1)是未知的需要求的假设:E(i)=Ai*E(1)+Bi*E(father)+Ci;//作为2式
设j为i的儿子
所以:E(child)=E(j)=Aj*E(1)+Bj*E(i)+Cj;
=>∑(E(child))=∑(Aj*E(1)+Bj*E(i)+Cj);
带入1式
=>E(i)=ki*E(1)+(1-ki-ei)/m *E(father)+(1-ki-ei)/m*∑(Aj*E(1)+Bj*E(i)+Cj)+(1-ki-ei);
=>(1-(1-ki-ei)/m*SUM(Bj))*E(i)=(ki+(1-ki-ei)/m*∑(Aj))*E(1)+(1-ki-ei)/m *E(father)+(1-ki-ei+(1-ki-ei)/m*∑(cj));
与上述2式对比得到:
Ai=(ki+(1-ki-ei)/m*∑(Aj)) / (1-(1-ki-ei)/m*∑(Bj))
Bi=(1-ki-ei)/m / (1-(1-ki-ei)/m*∑(Bj))
Ci=(1-ki-ei+(1-ki-ei)/m*∑(cj)) / (1-(1-ki-ei)/m*∑(Bj))
所以Ai,Bi,Ci只与i的孩子Aj,Bj,Cj和本身ki,ei有关
于是可以从叶子开始逆推得到A1,B1,C1
在叶子节点:
Ai=ki;
Bi=(1-ki-ei);
Ci=(1-ki-ei);
而E(1)=A1*E(1)+B1*0+C1;
=>E(1)=C1/(1-A1);
如果A1趋近于1则无解。注意这里eps设成1e-10,否则会WA(不要问我怎么知道的T-T)
Code(当然是自己实现滴):
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 50000 const double eps=1e-10; int t,n; struct haha{ int next,to; }edge[N*2]; int head[N],cnt=1; void add(int u,int v){ edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } double k[N],e[N],a[N],b[N],c[N]; void dfs(int x,int fa){ a[x]=b[x]=c[x]=0.0; double m(0),sumb(0),suma(0),sumc(0),temp=1.0-k[x]-e[x]; for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to!=fa){ m++; dfs(to,x); sumb+=b[to];suma+=a[to];sumc+=c[to]; } } if(x!=1) ++m; if(m==1&&x!=1){ a[x]=k[x];b[x]=1.0-k[x]-e[x];c[x]=b[x]; } else{ a[x]=(k[x]+temp/m*suma)/(1-temp/m*sumb); b[x]=(temp/m)/(1-temp/m*sumb); c[x]=(temp+temp/m*sumc)/(1-temp/m*sumb); } } int main(){ scanf("%d",&t); pos(u,1,t){ memset(edge,0,sizeof(edge)); memset(head,0,sizeof(head));cnt=1; scanf("%d",&n); pos(i,1,n-1){ int x,y;scanf("%d%d",&x,&y); add(x,y);add(y,x); } pos(i,1,n){ scanf("%lf%lf",&k[i],&e[i]); k[i]/=100;e[i]/=100; } dfs(1,0); if(fabs(1-a[1])<eps) printf("Case %d: impossible\\n",u); else printf("Case %d: %.6lf\\n",u,c[1]/(1-a[1])); } return 0; }
以上是关于[经典好题]HDU4035 Maze 期望树形DP的主要内容,如果未能解决你的问题,请参考以下文章