CF123E Maze 期望 树形dp

18 篇文章 0 订阅
17 篇文章 0 订阅

题目链接
题目链接是洛谷翻译过的。

题意:
给你一棵树,边权都是1,每一个点有一个是起点的概率和一个是终点的概率,你将以起点为根,开始在树上随机dfs,直到走到终点。求dfs从起点到终点的期望长度。n<=10w

题解:
我们考虑一条确定路径从s到t的期望步数的计算方法。我们发现,这个答案根据期望的线性性,我们可以拆成在这条路径上每个点到下一个点的期望步数之和。那么我们考虑如何求一个点到下一个点的期望步数。

一个点走到下一个点的过程中,可能先走遍其中的某几个子树,然后再走到想要走的方向。我们假设当前点的度数为 x x x,那么从当前点走到每一个点的概率都是 1 x \frac{1}{x} x1,而走进一个子树之后就会把整个子树全部遍历,由于去和回经过每条边两次,所以走到每个非目标点 y y y的贡献都是 1 x ∗ s i z e [ y ] ∗ 2 \frac{1}{x}*size[y]*2 x1size[y]2。由于我们随机选取当前点能到达的没有访问过的点走,所以对于任意当前点能到达两个点 a a a b b b,在随机选择点去走的情况下 a a a b b b前面和 b b b a a a前面的概率都是 1 2 \frac{1}{2} 21,于是刚才的贡献应该再乘 1 2 \frac{1}{2} 21,那么一个非两点在子树的贡献就是子树大小乘当前点的度数。

对于这个题的做法,我们是枚举每一个点作为终点时对答案的贡献,考虑起点在每个点为根的子树内的概率,我们其实由刚才的式子化简可以得到,在某个子树内的点的贡献就是子树大小,于是根据期望=概率*权值,以及期望的线性性,我们遍历每个点能到达的点以及他们的子树大小,然后乘概率和就是这个点的贡献,最后答案是对每个点的答案求和。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,hed[100010],cnt,sz[100010],fa[100010];
double ru[100010],chu[100010],sru,schu,ans;
struct node
{
    int to,next;
}a[200010];
inline void add(int from,int to)
{
    a[++cnt].to=to;
    a[cnt].next=hed[from];
    hed[from]=cnt;
}
inline void dfs(int x)
{
    sz[x]=1;
    for(int i=hed[x];i;i=a[i].next)
    {
        int y=a[i].to;
        if(y==fa[x])
        continue;
        fa[y]=x;
        dfs(y);
        ru[x]+=ru[y];
        sz[x]+=sz[y];
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n-1;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;++i)
    {
        scanf("%lf%lf",&ru[i],&chu[i]);
        sru+=ru[i];
        schu+=chu[i];
    }
    for(int i=1;i<=n;++i)
    ru[i]/=sru;
    dfs(1);
    for(int x=1;x<=n;++x)
    {
        for(int i=hed[x];i;i=a[i].next)
        {
            int y=a[i].to;
            if(y==fa[x])
            ans+=(1-ru[x])*(n-sz[x])*chu[x]/schu;
            else
            ans+=ru[y]*sz[y]*chu[x]/schu;
        }
    }
    printf("%.12lf\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值