题目描述
给出一棵树,每次随机等概率选择一未染黑的点,将它及其子树染黑。问期望多少次操作可以将树全部染黑。
Sol
期望的线性性公式:
其中
和
是两个随机事件(不一定要求独立)
用到这题上 , 要求整棵树被染黑的期望步数,可以转化为求每一个点被染黑的期望步数,然后加起来
怎么求一个点被染黑的期望步数呢?
显然一个点能被染黑当且仅当它自己在没有被染黑的情况下选择了它自己或着是它的祖先染黑 , 因为已经染黑就不能记步数了
考虑该事件中的贡献部分 , 因为祖先被染黑后自己也一定被染黑了 , 所以这时也不能算贡献,因为并没有增加步数 , 当且仅当选择的点恰好是自己的时候 , 这是自己一定没有被染黑 , 那么就要用掉一步,所以每一个点对答案的贡献是 ,因为有 个祖先(包括自己)
其实这里的一个点被染黑的期望步数应该是直接选择该点并染黑的期望步数,可以这么考虑,把一个点被染黑这个事件拆成因直接选择染黑和被影响而染黑 , 而被影响而染黑这个事件等价于直接选取该点的一个祖先染黑,它已经被考虑过了 , 所以只要算因直接选取而染黑该点的期望步数
本菜鸡对期望线性性的做法的理解:
拆分子事件后 , 把直接能决定该事件是否发生的事件列出
只考虑这些能决定该事件是否发生的事件,由此计算概率,并乘上对应的权值得出期望
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct edge{
int to,next;
}a[N<<1];
int head[N];int cnt=0;
inline void add(int x,int y){a[++cnt]=(edge){y,head[x]};head[x]=cnt;}
int n;
typedef long long ll;
typedef double db;
db ans=0.0;
void dfs(int u,int fa,int dep)
{
ans+=1.000/(db)(dep);
for(register int v,i=head[u];i;i=a[i].next){
v=a[i].to;
if(v==fa) continue;
dfs(v,u,dep+1);
}
return ;
}
int main()
{
scanf("%d",&n);
register int u,v;
for(register int i=1;i<n;++i){
scanf("%d %d",&u,&v);add(u,v);add(v,u);
}
dfs(1,0,1);
printf("%.9lf\n",ans);
}