hdu:4035Maze

题目链接

hdu4035

题意

有n个房间,由n-1条通道连通起来,实际上就形成了一棵树,从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的步数的期望值。

题解

设:i号点走出迷宫步数的期望为 Ei ,父亲为 Fi ,儿子为 Chi ,儿子数目为 m 那么E1即为所求。
容易写出:
对于叶子节点i:
Ei=kiE1+(1kiei)(EFi+1)=kiE1+(1kiei)EFi+(1kiei)
对于非叶子节点i:
Ei=kiE1+(1kiei)/m(EFi+1+(EChi+1))=kiE1+(1kiei)/mEFi+(1kiei)/mEChi+1kiei
我们发现,对于每个点,他的期望都与他父亲的期望和1号点的期望有关。我们可以写出这种形式:
Ei=AiE1+BiEFi+Ci
对于非叶子节点 Ci 的值还与它的儿子有关。设它的儿子为j。
Ej=(AjE1+BjEFj+Cj)=(AjE1+BjEi+Cj)
将它代入上式:
Ei=kiE1+(1kiei)/mEFi+(1kiei)/m(AjE1+BjEi+Cj)+1kiei
化简后有:
(1(1kiei)/mBj)Ei=(ki+(1kiei)/mAj)E1+(1kiei)/mEFi+(1kiei)+(1kiei)/mCj
即:
Ai=(ki+(1kiei)/mAj)/(1(1kiei)/mBj)Bi=(1kiei)/m/(1(1kiei)/mBj)Ci=((1kiei)+(1kiei)/mCj)/(1(1kiei)/mBj)
现在 Ai,Bi,Ci 只与他们的儿子 kiei 有关了。于是可以从下往上递推,推出 A1,B1,C1 即可。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;

struct edge{
    int x,next;
}ed[20010];
int first[10010],du[10010],tot,n,m,x,y,T,id;
double a[10010],b[10010],c[10010],e[10010],k[10010];

void add(int x,int y){
    ed[++tot].x=y;
    ed[tot].next=first[x];
    first[x]=tot;
} 
bool dfs(int x,int y){
    int m=du[x]; 
    a[x]=k[x]; 
    b[x]=(1-k[x]-e[x])/m;
    c[x]=1-k[x]-e[x];
    double tmp=0;
    for(int i=first[x];i;i=ed[i].next)
    if(ed[i].x!=y){
        if(!dfs(ed[i].x,x)) return false;
        a[x]+=(1-k[x]-e[x])/m*a[ed[i].x];
        c[x]+=(1-k[x]-e[x])/m*c[ed[i].x];
        tmp+=(1-k[x]-e[x])/m*b[ed[i].x];
    }
    if(fabs(tmp-1)<1e-9) return false;
    a[x]/=1-tmp;
    b[x]/=1-tmp;
    c[x]/=1-tmp;
    return true;
}
int main(){
    for(scanf("%d",&T);T;T--,id++){
        memset(first,0,sizeof(first));
        memset(du,0,sizeof(du));
        scanf("%d",&n); tot=0;
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
            du[x]++; du[y]++;
        }
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&k[i],&e[i]);
            k[i]/=100.0; e[i]/=100.0;
        }
        printf("Case %d: ",id+1);
        if(dfs(1,0)&&fabs(1-a[1])>1e-9) printf("%.6f\n",c[1]/(1-a[1]));
        else puts("impossible");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值