Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望

题目链接:点击打开链接

题意:给定n个点的一棵树

每次操作随机选任意一个点,把这个点和这个点的子树删去。

当把所有点删去则停止。

问操作次数的期望。

题解引用自:点击打开链接

删除的规则拥有一个非常好的性质:对于任意(u,v),选择u会导致删除v,那么选择u会删除的点集合一定包含选择了v以后会删除的点集合。

我们考虑换一种方式来实现删除的过程:

产生一个随机的1-n的排列P,从前往后依次尝试删除这些点,如果当前点已经被删除,就什么都不干,否则把次数+1,删除这个点以及他的所有后代。

通过这种方式产生的实际删除序列与题目原来规定的方式的概率分布是相同的。这一点是比较显然且非常容易证明的。

如果我们自己YY出来的过程进行了一半,排列P还有一个后缀等待解释,这个后缀中1到n号是实际仍然留在树中的点,n+1到 n+k号是实际已经不存在的点。那么1号点是下一次被选择的点的概率是

由于之前我们发现的性质,上述过程也可以这样说:

产生一个随机的1-n的排列P,从前往后删除这些点,如果当前点未删除,把次数+1,之后无条件删除这个点以及他的所有后代。

(与原先那个的区别,尝试YY几个类似的删东西的题目,然后尝试用这种方法做就能体会了。。)

这有什么用呢?由期望的线性性,我们最后要计算的是E(总操作次数)=sigma{E([每个结点u是因为选中了自己而删去的])},之后那个谓词成立当且仅当在我们生成的排列P中,u出现在他所有的祖先之前,因此这一项的期望值就是u在树中深度的倒数。把所有深度倒数加起来就是答案。

#include<bits/stdc++.h>
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(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');
    ret*=sgn;
    return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
using namespace std;
const int N = 100005;
struct Edge{
    int to, nex;
}edge[N<<1];
int head[N], edgenum;
void add(int u, int v){
    Edge E = {v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
void init(){memset(head ,-1, sizeof head); edgenum = 0;}
int dep[N], n;
void dfs(int u, int fa, int deep){
    dep[u] = deep;
    for(int i = head[u]; ~i; i = edge[i].nex){
        int v = edge[i].to;
        if(v == fa)continue;
        dfs(v, u, deep+1);
    }
}
void input(){
    init();
    for(int i = 1, u, v; i < n; i++)
    {
        cin>>u>>v;
        add(u, v); add(v, u);
    }
}
int main(){
    ios::sync_with_stdio(false);
    while(cin>>n){
        input();
        dfs(1,1,1);
        double ans = 0;
        for(int i = 1; i <= n; i++)
        {
            ans += 1.0/dep[i];
        }
        printf("%.10f\n", ans);
    }
    return 0;
}
时间: 2024-08-07 17:00:58

Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望的相关文章

Codeforces.280C.Game on Tree(期望)

题目链接 参考:浅谈期望的线性性(可加性) Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望(这个的前半部分分析并没有看..) \(Description\) 给你一棵有\(n\)个白点的有根树,每次随机选择一个点,将它和它的子树中所有点染黑. 问期望操作多少次后所有点都被染黑? \(Solution\) 期望好玄啊..(好吧是我太弱) 因为概率具有可加性,一棵树可以分解为多棵子树,而子树分解的最终状态就是点,所以我们可以计算每个点的期望操作次

CodeForces 540D Bad Luck Island 概率dp

CodeForces 540D 应该是简单概率dp,由于写得少显得十分蠢萌 求期望逆推,求概率正推,大概是这么个意思,贴一发留恋 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double const int maxn=108; db dp[maxn][maxn][maxn]; int main() { int i,j,n,m,k,p; whi

LightOJ 1038 - Race to 1 Again (给一个数,用这个数的因数除以这个数,直到为1时,求除的次数的期望。)(概率)

题意:http://www.lightoj.com/volume_showproblem.php?problem=1038 题意:给一个数,用这个数的因数除以这个数,直到为1时,求除的次数的期望. 设一个数的约数有M个,E[n] = (E[a[1]]+1)/M+(E[a[2]]+1)/M+...+(E[a[M]]+1)/M 一个数最大的约数是它自己. 则有,E[n] = (E[a[1]]+1)/M+(E[a[2]]+1)/M+...+(E[n]+1)/M (M-1)*E[n]=E[a[1]]+E

Codeforces 148D Bag of mice (概率dp)

D. Bag of mice time limit per test:2 seconds memory limit per test:256 megabytes The dragon and the princess are arguing about what to do on the New Year's Eve. The dragon suggests flying to the mountains to watch fairies dancing in the moonlight, wh

Codeforces 518D Ilya and Escalator (概率dp)

Ilya and Escalator time limit per test: 2 seconds memory limit per test: 256 megabytes Ilya got tired of sports programming, left university and got a job in the subway. He was given the task to determine the escalator load factor. Let's assume that

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Codeforces 513C Second price auction 概率dp 求期望

题目链接:点击打开链接 题意: 有n个人去竞拍一件商品,下面给出n个区间表示每个人出的价是区间中随机的一个数(概率均等) 则第一名需要付的钱是第二名的竞拍价格(允许并列第一名) 求支付的钱的期望. 思路: 枚举付的钱,然后求付这个钱的概率,相乘后求和即可. 对于确定支付x元 分类讨论一下: 1.第一名出价大于x 枚举第一名,然后剩下来的人至少一个人出x元,其他人出<=x, P(剩下来的人一个人出x元,其他人出<=x) = P(剩下来的人出价<=x) - P(剩下的人出价<x) 2.

Codeforces 513G1 513G2 Inversions problem 概率dp

题目链接:点击打开链接 题意: 给定n ,k 下面n个数表示有一个n的排列, 每次操作等概率翻转一个区间,操作k次. 问: k次操作后逆序数对个数的期望. 思路: dp[i][j]表示 a[i] 在a[j] j前面的概率 初始就是 dp[i][j]  = 1( i < j ) 则对于翻转区间 [i, j], 出现的概率 P = 1 / ( n * (n+1) /2) 并且会导致 [i, j]内元素位置交换,枚举这次翻转的区间时所有的转移情况 #include <stdio.h> #inc