【HDU4035】Maze-期望DP+树形DP

测试地址:Maze

题目大意:有一个树形的迷宫,有N个房间(标号为1~N)以及N-1条通道将它们连通,一开始在1号房间,每进入一个房间i,有k[i]的概率被陷阱杀死回到房间1,有e[i]的概率找到出口逃离迷宫,如果没有找到出口也没有被杀,那么就在与该房间相连的通道中等概率随机选一条走,求逃离迷宫所需要走的通道数的期望值(如果不能逃离输出impossible)。

做法:求期望采用逆推的方式。设f[i]表示从房间i开始走,逃离迷宫所需要走的通道数的期望值,令fa[i]为点i的父亲(整棵树以1为根时),deg[i]为点i的度数,我们知道对于每个叶子节点有:f[i]=k[i]*f[1]+(1-k[i]-e[i])*(f[fa[i]]+1),对于每个节点有:f[i]=k[i]*f[1]+(1-k[i]-e[i])/deg[i]*Σ(f[j]+1),其中j满足点i和点j之间有直接连边。我们可以发现,一个节点的期望值跟三个部分有关:点1的期望,父亲节点的期望,儿子节点的期望,而儿子节点的期望也和这三个部分有关,一直下到叶子节点,因为叶子节点没有儿子节点,所以我们可以把叶子节点作为突破口。我们可以将每个点的期望表示成这样一个式子:f[i]=x*f[1]+y*f[fa[i]]+z,显然对于叶子节点有:x=k[i],y=1-k[i]-e[i],z=1-k[i]-e[i]。然后对于其他节点,因为其儿子节点的父亲节点就是它本身,所以我们可以用待定系数法求出这个节点的期望式。在最后,我们可以求出f[1]的期望式,即f[1]=x*f[1]+y*f[fa[1]]+z,由于fa[1]没有意义,我们把它舍去,变化一下式子就可以得到:f[1]=z/(1-x),这就是我们要求的答案了。注意当x无限趋近于1时(|x-1|≤1e-9),f[1]无法解出,这时就输出impossible就可以了。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define eps 1e-9
using namespace std;
int T,n,first[10010],tot,fa[10010];
double f1[10010],f2[10010],f3[10010],k[10010],e[10010]; //f1,f2,f3即上文提到的系数x,y,z
struct edge {int v,next;} E[20010];
bool flag;

void insert(int a,int b)
{
  E[++tot].v=b,E[tot].next=first[a],first[a]=tot;
}

void treedp(int v)
{
  double s=1,a;
  f1[v]=f2[v]=f3[v]=0;
  for(int i=first[v];i;i=E[i].next)
    if (E[i].v!=fa[v])
	{
	  fa[E[i].v]=v;
	  treedp(E[i].v);
	  f1[v]+=f1[E[i].v];
	  f2[v]+=f2[E[i].v];
	  f3[v]+=f3[E[i].v];
	  s+=1.0;
	}
  if (v==1) s-=1.0;
  f1[v]=f1[v]*(1-k[v]-e[v])/s;
  f2[v]=f2[v]*(1-k[v]-e[v])/s;
  f3[v]=f3[v]*(1-k[v]-e[v])/s;
  a=1-f2[v];
  f1[v]+=k[v];
  f2[v]=(1-k[v]-e[v])/s;
  f3[v]+=(1-k[v]-e[v]);
  f1[v]/=a,f2[v]/=a,f3[v]/=a;
}

int main()
{
  scanf("%d",&T);
  for(int t=1;t<=T;t++)
  {
    scanf("%d",&n);
	memset(first,0,sizeof(first));
	tot=0;
	for(int i=1,a,b;i<n;i++)
	{
	  scanf("%d%d",&a,&b);
	  insert(a,b),insert(b,a);
	}
	for(int i=1;i<=n;i++)
	{
	  scanf("%lf%lf",&k[i],&e[i]);
	  k[i]/=100.0,e[i]/=100.0;
	}
	
	fa[1]=0;
	treedp(1);
	
	if (fabs(f1[1]-1)<=eps) printf("Case %d: impossible
",t);
	else printf("Case %d: %.6lf
",t,f3[1]/(1-f1[1]));
  }
  
  return 0;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793763.html