Codeforces 280C Game on Tree 题解 (期望)

本文介绍了一道来自Codeforces的题目,题目要求计算在随机等概率选择节点进行染色的情况下,将整棵树染黑的期望步数。通过对每个节点染黑的期望次数进行计算(该期望值等于其子节点数量加1),并求和,得到整体的期望步数。文章提供了思路解析和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:
CF
洛谷

题意简述

给定一个树,初始全是白色,每次会随机等概率选择一个白点,把它和子树都染黑。被染黑过的点再被染第二次还是黑的。。。问:把整个树都染黑的期望步数。

数据

输入

第一行一个正整数 n ( n &lt; = 1 0 5 ) n(n&lt;=10^5) n(n<=105),表示这个树有 n n n个点。
接下来 n − 1 n-1 n1行,每行两个正整数 a , b ( 1 &lt; = a , b &lt; = n , a ! = b ) a,b(1&lt;=a,b&lt;=n,a!=b) a,b(1<=a,b<=n,a!=b),表示 a , b a,b a,b之间有一个连边。数据保证是一个合法的树。

输出

如题意简述。输出把整个树都染黑的期望步数。

思路

根据期望的线性性,我们珂以求出每个点被染黑的期望次数,然后加起来,就是总共被染黑的期望次数。

求期望,分两步:概率和取值
先求概率。
对于每个点 i i i,能把它染黑的应该有 d e e p i deep_i deepi个点。( d e e p i deep_i deepi表示深度,满足: d e e p r o o t = 1 , d e e p i = d e e p f a t h e r _ i + 1 deep_{root}=1,deep_i=deep_{father\_i}+1 deeproot=1,deepi=deepfather_i+1)。然后我们在等概率选择点的时候,就会有 1 d e e p i \frac{1}{deep_i} deepi1的概率把点 i i i染黑。
那么,取值是多少呢?显然,如果要染一个单点,一步就够了。所以取值就是 1 1 1
至此求出第 i i i个点被染黑的期望次数是 1 d e e p i \frac{1}{deep_i} deepi1。我们枚举 i i i,把这个值加起来即珂。

代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
    #define real double
    #define N 100100
    class Graph//图
    {
        public:
            int head[N];
            int EdgeCount;
            struct Edge
            {
                int To,Label,Next;
            }Ed[N<<1];

            void clear()
            {
                memset(Ed,-1,sizeof(Ed));
                memset(head,-1,sizeof(head));
                EdgeCount=0;
            }
            void AddEdge(int u,int v,int w)
            {
                ++EdgeCount;
                Ed[EdgeCount]=(Edge){v,w,head[u]};
                head[u]=EdgeCount;
            }

            int Start(int u)
            {
                return head[u];
            }
            int To(int u)
            {
                return Ed[u].To;
            }
            int Label(int u)
            {
                return Ed[u].Label;
            }
            int Next(int u)
            {
                return Ed[u].Next;
            }
    }G;void Add(int u,int v,int w){G.AddEdge(u,v,w);G.AddEdge(v,u,w);}
    int n;
    void Input()
    {
        scanf("%d",&n);
        for(int i=1;i<n;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            Add(u,v,1);
        }
    }

    int deep[N];
    void DFS(int u,int f)
    {
        deep[u]=(f==-1)?(1):(deep[f]+1);
        //根的deep是1
        for(int i=G.Start(u);~i;i=G.Next(i))
        {
            int v=G.To(i);
            if (~v and v!=f)
            {
                DFS(v,u);
            }
        }
    }
    void Soviet()
    {
        DFS(1,-1);
        real ans=0;
        for(int i=1;i<=n;++i)
        {
            ans+=(1.00/(1.00*deep[i]));//暴力加值
        }
        printf("%.10f\n",ans);//我输出了10位,但是这个不重要,只要超过8位应该都是过了的,开了SPJ
    }

    void IsMyWife()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        G.clear();
        Input();
        Soviet();
    }
};
int main()
{
    Flandle_Scarlet::IsMyWife();
    return 0;
}

回到总题解界面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值