HDU 4035 Maze [概率DP]

Description

When wake up, lxhgww find himself in a huge maze. 

The maze consisted by N rooms and tunnels connecting these rooms. Each pair of rooms is connected by one and only one path. Initially, lxhgww is in room 1. Each room has a dangerous trap. When lxhgww step into a room, he has a possibility to be killed and restart from room 1. Every room also has a hidden exit. Each time lxhgww comes to a room, he has chance to find the exit and escape from this maze. 

Unfortunately, lxhgww has no idea about the structure of the whole maze. Therefore, he just chooses a tunnel randomly each time. When he is in a room, he has the same possibility to choose any tunnel connecting that room (including the tunnel he used to come to that room). 
What is the expect number of tunnels he go through before he find the exit? 

题意:

给出一个迷宫,路径为一棵树,树上有N个节点,从1出发,每走到一个节点可能会发生三种事件:

Ki的概率发生被杀回到起点1;

Ei的概率发生成功逃出迷宫;

剩下的概率发生随机选择一条路径到下一个节点。(等概率选择)

问逃出迷宫前需要走的步数的期望值。


范围:

N<=10000,30组样例


解法:

范围很明显表示时间复杂度为On或者On*logn,考虑概率DP,DP[I]表示从I点出发,需要走的步数的期望值,目标是求解DP[1]。

那么很明显这个转移过程是由环的,需要设未知数,首先列出转移方程:

DP[I]=Ki*DP[1]+(1-Ki-Ei)/M *(ΣDP[son] +DP[father])+1-Ki-Ei

发现应该自底向上DP,所以对于I来说DP[SON]是已知的,其他都是未知的,所以方程转换为:

DP[I]=A[i]*DP[i] + B[i]*DP[father] + C[i]

根据原方程得出A,B,C的转移方程:

设P=(1-k[I]-E[I])/ M ,M为连出去的边数,即P为走其中一条边的概率

A[I]=K[I]+P*ΣA[son];

B[I]=P

C[I]=1-K[I]-E[I]+P*ΣC[son]

最后得到等式DP[1]=A[1]*DP[1]+C[1]

化简得:

DP[1]=C[1]/(1.0-A[1])

可知A[1]→1.0时,无解


代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;


#define NN 10010
double dp[NN];
double a[NN],b[NN],c[NN],k[NN],e[NN];
int ptx[NN],lnum,n;
struct edge{
    int v,next;
    edge(){}
    edge(int v,int next):v(v),next(next){}
}ed[NN*2];
void addline(int x,int y){
    ed[lnum]=edge(y,ptx[x]);
    ptx[x]=lnum++;
}
void init(){
    lnum=0;
    rep(i,0,n)dp[i]=a[i]=b[i]=c[i]=0;
    rep(i,0,n)ptx[i]=-1;
}

void dfs(int x,int fa){
    double ta,tb,tc;
    ta=tb=tc=0;
    int m=(x==1?0:1);
    gson(i,x){
        int y=ed[i].v;
        if(y==fa)continue;
        dfs(y,x);
        m++;
        ta+=a[y];
        tb+=b[y];
        tc+=c[y];
    }
    double p=(1.0-k[x]-e[x])/double(m);
    if(x==1){
        a[x]=k[x]+ta*p+tb*p;
        c[x]=1.0-k[x]-e[x]+tc*p;
        return;
    }
    if(m==1){
        a[x]=k[x];
        b[x]=p;
        c[x]=1.0-k[x]-e[x];
    }
    if(m!=1){
        a[x]=k[x]+ta*p;
        b[x]=p;
        c[x]=1.0-k[x]-e[x]+tc*p;
    }
    a[x]/=(1.0-tb*p);
    b[x]/=(1.0-tb*p);
    c[x]/=(1.0-tb*p);
}

int main(){
    tdata{
        scanff(n);
        init();
        rep(i,1,n-1){
            int x,y;
            scanff(x);scanff(y);
            addline(x,y);
            addline(y,x);
        }
        rep(i,1,n){
            scanff(k[i]);scanff(e[i]);
            k[i]/=100.0;e[i]/=100.0;
        }
        dfs(1,0);
        double ans=c[1]/(1.0-a[1]);
        double eps=1e-9;
        printf("Case %d: ",cas);
        if(fabs(a[1]-1.0)<eps)printf("impossible\n");
        else printf("%lf\n",ans);
    }
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值