[SHOI2014]概率充电器

题目:
https://ac.nowcoder.com/acm/problem/20589

n − 1 n-1 n1个导线联通 n n n个充电元件,每个充电元件有 a i a_i ai概率直接进入充电状态,每个导线有 b i b_i bi概率导电,而且每个进入充电状态的元件可以通过导电的导线使其他元件进入充电状态。求进入充电状态的元件个数的期望是多少?

思路:

  首先题目中给出的一个点被充电的条件是自己有电周边点有电且连接的边导电,如果直接计算要用容斥。但是我们可以计算一个点不充电的概率,那么就是自己不直接进入充电状态周围的点不会有电传给该点,因为周围不会有电传给该点的事件都是独立的,可以直接用乘法原理。
p ( u ) p(u) p(u)表示点 u u u不充电的概率, e ( u , v ) e(u,v) e(u,v)表示 ( u , v ) (u,v) (u,v)边导电的概率,则有
p ( u ) = ( 1 − a u ) ∏ ( u , v ) ∈ E [ 1 − e ( u , v ) + e ( u , v ) p ( v ) ] p(u)=(1-a_u)\prod_{(u,v)\in E}[1-e(u,v)+e(u,v)p(v)] p(u)=(1au)(u,v)E[1e(u,v)+e(u,v)p(v)]
解释就是首先它自己不能亮,然后枚举所有相邻的点,如果边不能导电那就没问题,如果边导电了相邻点就不能导电。
  设 f ( u ) f(u) f(u)表示是 u u u不被它儿子(含自身)导电的概率。则上面那个式子相当于对每个点 u u u,以 u u u为根按照下面式子 d p dp dp
f ( u ) = ( 1 − a u ) ∏ v ∈ s o n ( u ) [ 1 − e ( u , v ) + e ( u , v ) f ( v ) ] f(u)=(1-a_u)\prod_{v\in son(u)}[1-e(u,v)+e(u,v)f(v)] f(u)=(1au)vson(u)[1e(u,v)+e(u,v)f(v)]
p ( u ) = f ( u ) p(u)=f(u) p(u)=f(u),因为对于根来说,周围所有的点不传电过来就是所有的儿子节点不传电过来。但是时间复杂度太高,考虑换根 d p dp dp
  先随便确定一个根,把无根树变成有根树 G r o o t G_{root} Groot进行一次上面式子的 d p dp dp,求出所有的 f f f函数值, f ( u ) f(u) f(u)表示在 G r o o t G_{root} Groot d p dp dp得到的函数值, p ( u ) p(u) p(u)表示以 u u u为根 d p dp dp得到的函数值。
注意: 接下来分析中点与点的关系都是在 G r o o t G_{root} Groot下(结合图)。
在这里插入图片描述

对于不是根的点 u u u,如果要以点 u u u为根 d p dp dp,则
p ( u ) = f ′ ( u ) = ( 1 − a u ) ∏ v ∈ s o n ( u ) ∪ { f a } [ 1 − e ( u , v ) + e ( u , v ) f ′ ( v ) ] = ( 1 − a u ) ∏ v ∈ s o n ( u ) [ 1 − e ( u , v ) + e ( u , v ) f ( v ) ] + 1 − e ( u , f a ) + e ( u , f a ) f ′ ( f a ) = f ( u ) + 1 − e ( u , f a ) + e ( u , f a ) f ′ ( f a ) \begin{aligned} p(u)&=f^{'}(u)=(1-a_u)\prod_{v\in son(u)\cup \{fa\}}[1-e(u,v)+e(u,v)f^{'}(v)]\\ &=(1-a_u)\prod_{v\in son(u)}[1-e(u,v)+e(u,v)f(v)]+1-e(u,fa)+e(u,fa)f^{'}(fa)\\ &=f(u)+1-e(u,fa)+e(u,fa)f^{'}(fa)\\ \end{aligned} p(u)=f(u)=(1au)vson(u){fa}[1e(u,v)+e(u,v)f(v)]=(1au)vson(u)[1e(u,v)+e(u,v)f(v)]+1e(u,fa)+e(u,fa)f(fa)=f(u)+1e(u,fa)+e(u,fa)f(fa)
f ′ f^{'} f表示以 u u u为根 d p dp dp的函数值。对于在 G r o o t G_{root} Groot中就是点 u u u的儿子,在以 u u u为根也是,所以 f ( v ) = f ′ ( v ) f(v)=f^{'}(v) f(v)=f(v)。而
f ′ ( f a ) = ( 1 − a f a ) ∏ ( f a , v ) ∈ E , v ≠ u [ 1 − e ( f a , v ) + e ( f a , v ) f ′ ( v ) ] = ( 1 − a f a ) ∏ ( f a , v ) ∈ E , v ≠ u [ 1 − e ( f a , v ) + e ( f a , v ) f ′ ′ ( v ) ] = ( 1 − a f a ) ∏ ( f a , v ) ∈ E [ 1 − e ( f a , v ) + e ( f a , v ) f ′ ′ ( v ) ] 1 − e ( f a , u ) + e ( f a , u ) f ′ ′ ( u ) = p ( f a ) 1 − e ( f a , u ) + e ( f a , u ) f ( u ) \begin{aligned} f^{'}(fa)&=(1-a_{fa})\prod_{(fa,v)\in E,v\neq u}[1-e(fa,v)+e(fa,v)f^{'}(v)]\\ &=(1-a_{fa})\prod_{(fa,v)\in E,v\neq u}[1-e(fa,v)+e(fa,v)f^{''}(v)]\\ &=\frac{(1-a_{fa})\prod_{(fa,v)\in E}[1-e(fa,v)+e(fa,v)f^{''}(v)]}{1-e(fa,u)+e(fa,u)f^{''}(u)}\\ &=\frac{p(fa)}{1-e(fa,u)+e(fa,u)f(u)}\\ \end{aligned} f(fa)=(1afa)(fa,v)E,v=u[1e(fa,v)+e(fa,v)f(v)]=(1afa)(fa,v)E,v=u[1e(fa,v)+e(fa,v)f(v)]=1e(fa,u)+e(fa,u)f(u)(1afa)(fa,v)E[1e(fa,v)+e(fa,v)f(v)]=1e(fa,u)+e(fa,u)f(u)p(fa)
f ′ ′ f{''} f表示以 f a fa fa为根 d p dp dp的函数值,对于 v v v G u G_{u} Gu时是 f a fa fa的儿子,在 G f a G_{fa} Gfa时也是 f a fa fa的儿子,所以 f ′ ′ ( v ) = f ′ ( v ) f^{''}(v)=f^{'}(v) f(v)=f(v) u u u G r o o t G_{root} Groot下是 f a fa fa的儿子,在 G f a G_{fa} Gfa的时候也是,所以 f ′ ′ ( u ) = f ( u ) f^{''}(u)=f(u) f(u)=f(u)。由于 f f f函数, p ( r o o t ) p(root) p(root)已经求出来了,所以只需要 D F S DFS DFS用父节点的 p p p值更新自己就行。

注意: 在计算 f ′ ( f a ) = p ( f a ) 1 − e ( f a , u ) + e ( f a , u ) f ( u ) f^{'}(fa)=\frac{p(fa)}{1-e(fa,u)+e(fa,u)f(u)} f(fa)=1e(fa,u)+e(fa,u)f(u)p(fa)时,如果
1 − e ( f a , u ) + e ( f a , u ) f ( u ) = 0 e ( f a , u ) [ 1 − f ( u ) ] = 1 \begin{aligned} 1-e(fa,u)+e(fa,u)f(u)&=0\\ e(fa,u)[1-f(u)]&=1 \end{aligned} 1e(fa,u)+e(fa,u)f(u)e(fa,u)[1f(u)]=0=1
因为 0 ≤ e ( f a , u ) , f ( u ) ≤ 1 0\le e(fa,u),f(u)\le 1 0e(fa,u),f(u)1,所以只能 e ( f a , u ) = 1 , f ( u ) = 0 e(fa,u)=1,f(u)=0 e(fa,u)=1,f(u)=0 f ( u ) = 0 f(u)=0 f(u)=0表明 u u u一定充电,所以直接令 p ( u ) = 0 p(u)=0 p(u)=0

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2e6;
struct Edge
{
    int v;
    double w;
} e[N];
int mm,n,fst[N],nxt[N];
double p[N],f[N],g[N];
void ade(int u,int v,double w)
{
    e[++mm]=(Edge)
    {
        v,w
    };
    nxt[mm]=fst[u],fst[u]=mm;
}
void dfs1(int u,int fa)
{
    f[u]=1-p[u];
    for(int i=fst[u]; i; i=nxt[i])
    {
        int v=e[i].v;
        if(v==fa)
            continue;
        dfs1(v,u);
        f[u]*=(1-e[i].w+e[i].w*f[v]);
    }
}
void dfs2(int u,int fa,int ei)
{
    if(u==1)
        g[u]=f[u];//如果u是根,那么什么都不用管.
    else
    {
        double tmp=1-e[ei].w+e[ei].w*f[u],P;
        if(!tmp)//特判
            g[u]=0;
        else
        {
            P=g[fa]/tmp;
            g[u]=f[u]*(1-e[ei].w+e[ei].w*P);
        }
    }
    for(int i=fst[u]; i; i=nxt[i])
    {
        int v=e[i].v;
        if(v==fa)
            continue;
        dfs2(v,u,i);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<n; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        ade(u,v,w*0.01),ade(v,u,w*0.01);
    }
    for(int i=1; i<=n; i++)
        scanf("%lf",p+i),p[i]*=0.01;
    dfs1(1,0),dfs2(1,0,0);
    double ans=0;
    for(int i=1; i<=n; i++)
        ans+=1-g[i];
    printf("%.6lf",ans);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值