Maze CodeForces - 123E

Maze CodeForces - 123E
题目描述:一个迷宫是一棵树(即一张无向图,其中任意两点之间仅有一条路径)。迷宫的起点和终点都按照某种概率随机选取。人们会在迷宫中用深度优先搜索的方法搜寻终点。如果有许多条可能的路径,会等概率地选取一条。考虑如下伪代码:

DFS(x)

if x == exit vertex then

    finish search

flag[x] <- TRUE

random shuffle the vertices' order in V(x) // here all permutations have equal probability to be chosen

for i <- 1 to length[V] do

    if flag[V[i]] = FALSE then

        count++;

        DFS(y);

count++;

V(x)是和x相邻的顶点列表。最初flag数组的值均为false。第一次DFS的参数是迷宫的入口节点。当搜索终止,变量count的值就是在迷宫中走的步数。
你的任务是计算在迷宫中从入口到出口,所走的期望步数。
对于每个点会给出两个值xi,yi,点i作为入口的概率是xi/sigma(xi),作为出口的概率是yi/sigma(yi)
n ≤ 100000

题解:首先这显然是一个概率dp(废话╮(╯▽╰)╭)。
然后枚举起点可以yy出一个O(n^2)的树形dp,显然不符合数据规模。
那么考虑以u为起点,v为终点的一条路径,u->v之间的边一定会经过一次(1~3号),v以后的边不可能经过(4~9),它们之间的边(10~17)可能访问0或2次(一进一出2次),取决于分叉时先访问了路径上的边1~3还是旁边的10~17。分叉点访问每条边的顺序是等概率的,所以之间的边访问次数的期望为1。
这里写图片描述

目前为止初步看dp还是O(n^2)的。但实际可以O(n)转移。

我们考虑如果当前点x为终点,那么当起点在x的子树中是,从子树向上到达x就会停止,所以可能经过的边数就是起点所属的x的儿子的size,那么期望就是size*子树中点作为起点的总概率*x为终点的概率。

如果起点在x的子树之外,那么x的子树都没有机会遍历到,而剩下的边都有可能被经过,所以对答案的贡献是(n-size)*(sigma(xi)-sigma(x的子树))*x为终点的概率。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
using namespace std;
const int N=100000+5;
int n,u,v,sz[N];
int cnt,fir[N],tar[N<<1],nxt[N<<1];
double x[N],y[N],s[N],e[N],sums[N],ans;
inline void link(int a,int b){
    tar[++cnt]=b,nxt[cnt]=fir[a],fir[a]=cnt;
}
void dfs(int x,int pre){
    sz[x]=1;
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=pre){
            dfs(tar[i],x);
            sz[x]+=sz[tar[i]];
            s[x]+=s[tar[i]];
            ans+=s[tar[i]]*sz[tar[i]]*e[x];
        }
    ans+=e[x]*(n-sz[x])*(1-s[x]);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d %d",&u,&v);
        link(u,v),link(v,u);
    }
    double X=0.0,Y=0.0;
    for(int i=1;i<=n;i++){
        scanf("%lf %lf",&x[i],&y[i]);
        X+=x[i],Y+=y[i];
    }
    for(int i=1;i<=n;i++)
        s[i]=x[i]/X,e[i]=y[i]/Y;
    dfs(1,0);
    printf("%.20f\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值