CF280C Game on tree(期望dp)
这道题算是真正意义上人生第一道期望的题?
题目大意:
给定一个n个点的,以1号点为根的树,每一次可以将一个点和它的子树全部染黑,求染黑所有点的期望
QwQ说实话,我对期望这种东西,一点也不理解。。。
根据期望的线性性,计算出每个点比选择的期望次数,然后直接相加
所以得出\(E(x) = \frac{1}{dep[x]}\)
这里之所以是$ \frac{1}{dep[x]}$是因为我们求的期望是每个点把自己及自己子树染黑的概率(而不是靠祖先)
或者换种说法:
整棵树的期望操作次数太大,难以找到方法。这时我们需要突破口。
该如何将大问题转化为小问题呢?我们发现,一棵树是可以分成好几颗子树的,而子树分解的最终状态就是所有的点。那么,我们是不是可以计算出 每个点被染黑的期望操作次数,然后相加就是整棵树的了?答案是当然可以。
这里需要注意的是,对于每个点的操作次数是指的在这个点上的操作。对于每一个点,如果其祖先被染黑了,它自己也会被顺带染黑,而这个对于该点来说是没有进行操作的。所以得出对于点x:\(E(x) = \frac{1}{dep[x]}\)
直接上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
const int maxm = 2e5+1e2;
int point[maxn],nxt[maxm],to[maxm];
double dep[maxn];
int vis[maxn];
int n,m;
int cnt;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void dfs(int x,double dp)
{
dep[x]=dp;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (!vis[p])
{
dfs(p,dp+1.0);
}
}
}
double ans=0;
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int x,y;
x=read(),y=read();
addedge(x,y);
addedge(y,x);
}
//cout<<"gg"<<endl;
dep[1]=1;
dfs(1,1.0);
for (int i=1;i<=n;i++)
{
ans=ans+1.0/dep[i];
}
printf("%.8lf",ans);
return 0;
}