• 【bzoj3566】[SHOI2014]概率充电器 树形概率dp


    题目描述

    著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
    “采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!”
    SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
    随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
    作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
    你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?

    输入

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

    输出

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

    样例输入

    3
    1 2 50
    1 3 50
    50 0 0

    样例输出

    1.000000


    题解

    树形概率dp

    先自下至上dp,求出每个子树中根节点不能工作的概率$f[x]$。其中工作需要子节点字数能工作且边存在。

    然后自上至下dp,更新每个点能工作的概率$g[x]$,计算出父树的贡献,方法同理。

    具体的dp方程:

    $f[x]=(1-w[x])*prod(1-f[to[i]]*val[i])$

    $g[1]=f[1]$

    $g[to[i]]=f[to[i]]*(1-(1-frac{g[x]}{1-(1-f[to[i]])*val[i]})*val[i])$。

    注意可能产生的除0的情况,此时$g[x]$必然等于0,特判一下就好了。

    最后的答案即为$sumlimits_{i=1}^ng[i]$。

    #include <cstdio>
    #define N 500010
    const double eps = 1e-7;
    int head[N] , to[N << 1] , next[N << 1] , cnt;
    double val[N << 1] , w[N] , f[N] , g[N];
    void add(int x , int y , double z)
    {
    	to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    }
    void dfs1(int x , int fa)
    {
    	int i;
    	f[x] = 1 - w[x];
    	for(i = head[x] ; i ; i = next[i])
    		if(to[i] != fa)
    			dfs1(to[i] , x) , f[x] *= 1 - (1 - f[to[i]]) * val[i];
    }
    void dfs2(int x , int fa)
    {
    	int i;
    	for(i = head[x] ; i ; i = next[i])
    	{
    		if(to[i] != fa)
    		{
    			if(1 - (1 - f[to[i]]) * val[i] < eps) g[to[i]] = f[to[i]] * val[i];
    			else g[to[i]] = f[to[i]] * (1 - (1 - g[x] / (1 - (1 - f[to[i]]) * val[i])) * val[i]);
    			dfs2(to[i] , x);
    		}
    	}
    }
    int main()
    {
    	int n , i , x , y;
    	double z , ans = 0;
    	scanf("%d" , &n);
    	for(i = 1 ; i < n ; i ++ ) scanf("%d%d%lf" , &x , &y , &z) , add(x , y , z / 100) , add(y , x , z / 100);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%lf" , &w[i]) , w[i] /= 100;
    	dfs1(1 , 0) , g[1] = f[1] , dfs2(1 , 0);
    	for(i = 1 ; i <= n ; i ++ ) ans += 1 - g[i];
    	printf("%.6lf
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    关闭NanoPi网卡指示灯(RTL8211E)
    C++有关mutable与const的使用
    全面理解JSX
    Typescript 面向对象 类和接口 属性访问权限 const、readonly和private
    ES6 Iterator迭代器 与 Generator生成器 如何用js封装一个遍历所有可迭代数据结构的方法
    Redux基础必知必会 reducer拆分 中间件 单向数据流
    TypeScript 泛型
    如何实现一个promise
    深入React源码理解ReactElement到底做了什么
    Redux applyMiddleWare 中间件
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7392084.html
Copyright © 2020-2023  润新知