[經典好題]HDU4035 Maze 期望樹形DP
阿新 • • 發佈:2017-10-30
images 一道 隧道 oss 即使 ios bsp esp hdu
這是我當年要刷的一道,自己想死活想不出來,於是去網上頹題解,然後:
這特麽怎麽想都想不出來啊!
題意是這個樣子滴:
有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