zoukankan      html  css  js  c++  java
  • 【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;
    }
    

     

  • 相关阅读:
    Qt 处理相机图像实时显示引入队列,防止数据读写冲突导致卡顿、崩溃
    OpenCV -- ffmpeg 视频输入输出VideoCapture和VideoWriter的使用
    OpenCV -- 伪彩 applyColorMap
    C++中内存拷贝函数(C++ memcpy)//深拷贝 浅拷贝
    逻辑运算符&&和&的区别、| 和 || 的区别
    openCV -- namedWindow( )函数用法总结
    var a="" 与a=" ",的区别;
    创建Node.js应用
    JS数值精度函数
    js字符串截取函数slice()、sunstring()、substr()
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7392084.html
Copyright © 2011-2022 走看看