1. 程式人生 > >[經典好題]HDU4035 Maze 期望樹形DP

[經典好題]HDU4035 Maze 期望樹形DP

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