题目链接
https://codeforces.com/problemset/problem/280/C
题意
给出一有根树,每次等概率删除一个点和其子树,问删完期望步数
思路
期望是有可加性的,删掉所有节点的期望就是所有节点被删的期望的和。
显然一个节点被删的花费是1,但是它能否贡献期望是有概率的,假设他的祖先节点比他先被删除,那么他是不可以产生贡献的,因此我们可以将他的期望看成是这样
E
(
x
)
=
{
1
,
x
先
于
祖
先
被
删
除
0
,
x
后
于
祖
先
被
删
除
E(x)=\left\{ \begin{array}{lr} 1,x 先于祖先被删除 & \\ 0,x后于祖先被删除 \end{array} \right.
E(x)={1,x先于祖先被删除0,x后于祖先被删除
那么根据期望的性质可以知道单个结点被删除的期望就应该是
1
∗
p
先
于
祖
先
+
0
∗
p
晚
于
祖
先
1*p_{先于祖先}+0*p_{晚于祖先}
1∗p先于祖先+0∗p晚于祖先
既然只考虑祖先,那么可以直接看一条链路,假如要精准删除掉x,显然概率应是1/deep[x]。那么相应的期望也就是他了。
综上,求出各点深度取倒数求和即可。
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=200505;
const int inf=0x3f3f3f3f;
int n,m,k;
vector<int>e[maxn];
int deep[maxn];
void dfs(int x,int fa){
deep[x]=deep[fa]+1;
for(auto y:e[x]){
if(y==fa) continue;
dfs(y,x);
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>n;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,1);
double ans=0;
for(int i=1;i<=n;i++){
ans+=1.0/deep[i];
}
cout<<fixed<<setprecision(15)<<ans<<endl;
}