• [SHOI2014]概率充电器


    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。

    做一个转化,转化为求不能进入充电状态的概率,最后用1减去即可
    那么设 (f[x]) 表示x不能被进入充电状态的概率,先考虑子树内部:
    (f[x]=(1-q[i])*prod{((1-f[u])*(1-p[i])+f[u])})
    上面的转移方程意思为分两种情况:
    1.子节点内部没有进入充电状态 (f[u])
    2.子节点内部已经进入充电状态,但是边断掉了 ((1-f[u])*(1-p[i]))
    最后从根下放再做一遍即可

    转载于巨佬PI sonhttp://www.cnblogs.com/Yuzao/p/7679317.html

    喻队太巨了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 struct Node
     7 {
     8   int next,to;
     9   double dis;
    10 }edge[1000001];
    11 int num,head[500001];
    12 double f[500001],ans,c[500001];
    13 void add(int u,int v,double d)
    14 {
    15   num++;
    16   edge[num].next=head[u];
    17   head[u]=num;
    18   edge[num].to=v;
    19   edge[num].dis=d;
    20 }
    21 void dfs1(int x,int fa)
    22 {int i;
    23   f[x]=1-c[x];
    24   for (i=head[x];i;i=edge[i].next)
    25     {
    26       int v=edge[i].to;
    27       if (v==fa) continue;
    28       dfs1(v,x);
    29       f[x]*=(1-edge[i].dis)*(1-f[v])+f[v];
    30     }
    31 }
    32 void dfs2(int x,int fa)
    33 {double tmp;
    34   int i;
    35   for (i=head[x];i;i=edge[i].next)
    36     {
    37       int v=edge[i].to;
    38       if (v==fa) continue;
    39       tmp=(1-edge[i].dis)*(1-f[v])+f[v];
    40       tmp=f[x]/tmp;
    41       f[v]*=(1-edge[i].dis)*(1-tmp)+tmp;
    42       dfs2(v,x);
    43     }
    44 }
    45 int main()
    46 {int i,n,u,v;
    47   double p;
    48   cin>>n;
    49   for (i=1;i<=n-1;i++)
    50     {
    51       scanf("%d%d%lf",&u,&v,&p);
    52       add(u,v,p/100.0);
    53       add(v,u,p/100.0);
    54     }
    55   for (i=1;i<=n;i++)
    56     scanf("%lf",&c[i]),c[i]/=100.0;
    57   dfs1(1,1);
    58   dfs2(1,1);
    59   for (i=1;i<=n;i++)
    60     ans+=1.0-f[i];
    61   printf("%.6lf
    ",ans);
    62 }
  • 相关阅读:
    记一次由于缓存导致的bug
    3 Task中的一些枚举 创建时候的、continue时候的
    2 Task中的延续和7种阻塞
    1 Task的简单实用
    关于内存溢出遇到的两种情况
    6 Wcf使用Stream传输
    5 wcf双工
    4 WCF中的RPC和OneWay
    3 WCF一些基础铺垫
    什么是三元表达式?“三元”表示什么意思?
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7739234.html
Copyright © 2020-2023  润新知