题意简述
给定一个树,初始全是白色,每次会随机等概率选择一个白点,把它和子树都染黑。被染黑过的点再被染第二次还是黑的。。。问:把整个树都染黑的期望步数。
数据
输入
第一行一个正整数
n
(
n
<
=
1
0
5
)
n(n<=10^5)
n(n<=105),表示这个树有
n
n
n个点。
接下来
n
−
1
n-1
n−1行,每行两个正整数
a
,
b
(
1
<
=
a
,
b
<
=
n
,
a
!
=
b
)
a,b(1<=a,b<=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;
}