码迷,mamicode.com
首页 > 其他好文 > 详细

[经典好题]HDU4035 Maze 期望树形DP

时间:2017-10-30 14:16:18      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:eps   src   imp   期望   nbsp   printf   next   idt   需要   

这是我当年要刷的一道,自己想死活想不出来,于是去网上颓题解,然后:

这特么怎么想都想不出来啊!

技术分享

题意是这个样子滴:

有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

标签:eps   src   imp   期望   nbsp   printf   next   idt   需要   

原文地址:http://www.cnblogs.com/Hallmeow/p/7753878.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!