• 【树形期望DP】BZOJ3566- [SHOI2014]概率充电器


    【题目大意】

    充电器由 n-1 条导线连通了 n 个充电元件。这n-1条导线均有一个通电概率p%,而每个充电元件本身有直接被充电的概率q[i]%。问期望有多少个充电元件处于充电状态?

    【思路】

    第一次做这种类型的题,还挺有意思的quq

    显然这n个充电元件构成一棵树,考虑用树形DP。

    我们用f1[i]表示当前元件仅仅因为直接充电或由孩子供电的概率,f2[i]表示当前元件处于充电状态的概率。

    前铺两个知识点:对于两个相互独立的事件A、B,P(A+B)=P(A)+P(B)-P(A)*P(B),P(A)=(P(A+B)-P(B))/(1-P(B))。(!!)

    我们可以用两次dfs求出f1、f2的值。

    ①对于f1,由于树中叶子节点不存在孩子,f1[叶子结点]=q[叶子结点],而对于非叶子节点,f1[i]=q[i]+∑f1[son]*p(注意这里的加法运算指代的是上述提到的概率加法)

    ②对于只由父亲贡献充电,我们考虑两个父子元件。对于父亲本身来说,给儿子充电的概率=总概率-儿子给自己充电的概率,pfa=f2[fa]-f1[now]*p(同样这里的减法用上面的概率加法)

       f2[now]=f1[now]+pfa*p(同理这里的加法用的是上述的概率加法)

    Over!!

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<vector>
     7 #define EPS (1e-8) 
     8 using namespace std;
     9 const int MAXN=500000+50;
    10 struct node
    11 {
    12     int to;
    13     double p;
    14 };
    15 vector<node> E[MAXN];
    16 double q[MAXN],f1[MAXN],f2[MAXN],ans;
    17 
    18 void addedge(int a,int b,double p)
    19 {
    20     E[a].push_back((node){b,p});
    21 }
    22 
    23 bool dcmp(double a)  
    24 {  
    25     return fabs(a-0)<EPS;  
    26 }  
    27 
    28 void dfs1(int u,int fa)
    29 {
    30     for (int i=0;i<E[u].size();i++)
    31     {
    32         int to=E[u][i].to;
    33         if (to!=fa) 
    34         {
    35             dfs1(to,u);
    36             f1[u]=f1[u]+f1[to]*E[u][i].p-f1[u]*f1[to]*E[u][i].p;
    37         }
    38     }
    39 }
    40 
    41 void dfs2(int u,int fa)
    42 {
    43     ans+=f2[u];
    44     for (int i=0;i<E[u].size();i++)
    45     {
    46         int to=E[u][i].to; 
    47         if (to!=fa)
    48         {
    49             if (dcmp(1.0-E[u][i].p*f1[to])) f2[to]=1.0;
    50             else
    51             {
    52                 double tmp=(f2[u]-E[u][i].p*f1[to])/(1.0-E[u][i].p*f1[to]);
    53                 f2[to]=f1[to]+tmp*E[u][i].p-f1[to]*tmp*E[u][i].p;
    54             }
    55             dfs2(to,u);
    56         }
    57     }
    58 }
    59 
    60 void init()
    61 {
    62     int n;
    63     scanf("%d",&n);
    64     for(int i=0;i<n-1;i++)
    65     {
    66         int a,b;
    67         double p;
    68         scanf("%d%d%lf",&a,&b,&p);
    69         addedge(a,b,p/100); 
    70         addedge(b,a,p/100);
    71     }
    72     for (int i=1;i<=n;i++)
    73     {
    74         scanf("%lf",&q[i]);
    75         f1[i]=q[i]/100;
    76     }
    77 }
    78 
    79 void solve()
    80 {
    81     dfs1(1,0);
    82     f2[1]=f1[1];
    83     dfs2(1,0);
    84     printf("%.6lf",ans);
    85 }
    86 
    87 int main()
    88 {
    89     init();
    90     solve();
    91     return 0;
    92 }
  • 相关阅读:
    十分钟-Nginx 入门到上线
    83.面向忙碌开发者的 Android 知识点收录 (转)
    技术人,为什么需要构建知识图谱 (转载)
    C# 4.0四大新特性代码示例与解读
    .NET 项目代码风格要求
    .NET 推荐博客
    C# 五、谈扩展方法的理解
    ASP.NET 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)
    ASP.NET 你必须知道的EF知识和经验
    Linq表达式、Lambda表达式你更喜欢哪个?
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5780368.html
Copyright © 2020-2023  润新知