BZOJ_3566_[SHOI2014]概率充电器_概率+树形DP

BZOJ_3566_[SHOI2014]概率充电器_概率+树形DP

Description

著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!

SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?

Input

第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的
充电元件,通电概率为 p%。
第 n+2 行 n 个整数:qi。表示 i 号元件直接充电的概率为 qi%。

Output

输出一行一个实数,为进入充电状态的元件个数的期望,四舍五入到六位小数

Sample Input

3
1 2 50
1 3 50
50 0 0

Sample Output

1.000000

HINT

对于 100%的数据,n≤500000,0≤p,qi≤100。


求通电的元件期望个数等价于求每个点通电的概率,然后加一起。

设F[x]表示x的子树不给x供电的概率。

需要满足x不带电,且对于所有儿子,要么儿子不带电,要么儿子带电,连得这条边不带电。

f[x]=(1-w[x])*(f[to]+(1-f[to])*(1-val[i]))。

设g[x]表示x的父亲不给x供电的概率。

需要先求一个fa[x]不带电(没有儿子的影响下)的概率,然后同上。

这个的概率是(f[fa[x]]*g[fa[x]])/(f[x]+(1-f[x])*(1-val[i]))。

最后每个点带电的概率就是1-f[x]*g[x]。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline char nc() {
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
    int x=0; char s=nc();
    while(s<'0'||s>'9') s=nc();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
    return x;
}
typedef double f2;
#define N 500050
int head[N],to[N<<1],nxt[N<<1],n,cnt;
f2 val[N<<1],w[N],f[N],g[N],ans[N],sum;
inline void add(int u,int v,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w/100.0;
}
void dfs1(int x,int y) {
    int i;
    f[x]=1-w[x];
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dfs1(to[i],x);
            f[x]=f[x]*(f[to[i]]+(1-f[to[i]])*(1-val[i]));
        }
    }
}
void dfs2(int x,int y) {
    ans[x]=1-f[x]*g[x];
    sum+=ans[x];
    int i;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            f2 tmp=(1-ans[x])/(f[to[i]]+(1-f[to[i]])*(1-val[i]));
            g[to[i]]=tmp+(1-tmp)*(1-val[i]);
            dfs2(to[i],x);
        }
    }
}
int main() {
    n=rd();
    register int i,x,y,z;
    for(i=1;i<n;i++) {
        x=rd(); y=rd(); z=rd(); add(x,y,z); add(y,x,z);
    }
    for(i=1;i<=n;i++) w[i]=rd()/100.0;
    dfs1(1,0);
    g[1]=1;
    dfs2(1,0);
    printf("%.6f
",sum);
}

原文地址:https://www.cnblogs.com/suika/p/9237578.html