一、题目
二、解法
其实这道题主要考察对期望的理解。
0x01 错解
设
d
p
[
u
]
dp[u]
dp[u]为
u
u
u点被点亮的期望,很容易想到的思路是先跑子树内的,再跑子树外的,转移是难点。
一开始写的转移是
d
p
[
u
]
=
∑
d
p
[
v
]
×
c
+
q
[
u
]
dp[u]=\sum dp[v]\times c+q[u]
dp[u]=∑dp[v]×c+q[u],也就是暴力加起来。
子树外的转移就省略了吧,反正也是错的。
思考问题到底在哪里,其实就是交集不能求和,也就是我们只需要有一个地方给
u
u
u供电,但存在多个地方给
u
u
u供电的情况,我们就成功的
g
g
gg
gg了。
0x02 改变状态定义
上文说明了求被点亮的期望是很难的,那我们换一种思路,定义
d
p
[
u
]
dp[u]
dp[u]为
u
u
u不被点亮的期望,为了实现方便,定义
d
p
[
u
]
[
0
/
1
]
dp[u][0/1]
dp[u][0/1]为 单独考虑子树内
/
/
/子树外 不被点亮的期望,考虑转移。
- 子树内, d p [ u ] [ 0 ] = ( ∏ 1 − c + d p [ v ] [ 0 ] ) × ( 1 − p [ i ] ) dp[u][0]=(\prod 1-c+dp[v][0])\times (1-p[i]) dp[u][0]=(∏1−c+dp[v][0])×(1−p[i]),这个 d p dp dp式的本质是分类讨论,也就是当边断开的期望加上边不断开并且 v v v没有亮,在乘上 u u u不亮的期望。
- 子树外, d p [ v ] [ 1 ] = 1 − c + ( d p [ u ] [ 1 ] × d p [ u ] [ 0 ] / ( 1 − c + d p [ v ] [ 0 ] × c ) ) × c dp[v][1]=1-c+(dp[u][1]\times dp[u][0]/(1-c+dp[v][0]\times c))\times c dp[v][1]=1−c+(dp[u][1]×dp[u][0]/(1−c+dp[v][0]×c))×c,也就是先算出 f a fa fa不亮的期望乘上边不断的期望,再加上边断掉的期望,注意小区 v v v子树对于 u u u的贡献,除掉即可。
最后答案即为 ∑ i = 1 n 1 − d p [ i ] [ 0 ] × d p [ i ] [ 1 ] \sum^{n}_{i=1} 1-dp[i][0]\times dp[i][1] ∑i=1n1−dp[i][0]×dp[i][1],时间复杂度 O ( n ) O(n) O(n)。
#include <cstdio>
#define eps 1e-9
const int MAXN = 500005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,tot,f[MAXN],q[MAXN];
double ans,dp[MAXN][2];
struct edge
{
int v,c,next;
}e[2*MAXN];
void dfs1(int u,int fa)
{
dp[u][0]=(1-1.0*q[u]/100);
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;double c=1.0*e[i].c/100;
if(v==fa) continue ;
dfs1(v,u);
dp[u][0]*=(1-c+dp[v][0]*c);
}
}
void dfs2(int u,int fa)
{
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;double c=1.0*e[i].c/100;
if(v==fa) continue;
if(1-c+dp[v][0]*c>eps)//解决精度问题,太小了就把它当不存在
dp[v][1]=1-c+(dp[u][1]*dp[u][0]/(1-c+dp[v][0]*c))*c;
else
dp[v][1]=1-c;
dfs2(v,u);
}
}
int main()
{
n=read();
for(int i=2;i<=n;i++)
{
int u=read(),v=read(),c=read();
e[++tot]=edge{v,c,f[u]},f[u]=tot;
e[++tot]=edge{u,c,f[v]},f[v]=tot;
}
for(int i=1;i<=n;i++)
q[i]=read();
dfs1(1,0);
dp[1][1]=1;
dfs2(1,0);
for(int i=1;i<=n;i++)
ans+=(1-dp[i][0]*dp[i][1]);
printf("%.6lf",ans);
}