zoukankan      html  css  js  c++  java
  • 【题解】SHOI2014概率充电器

      首先发现答案就是每个节点有电的概率之和。有电的概率牵扯太广不好求,所以转化为求没有电的概率。这题最难的部分在于:一个节点如果有电,可以来自儿子,也可以来自父亲。我们考虑将这两个部分分离开来:建立状态 (g[i]) 和 (f[i]) 分别表示一个节点只考虑子树节点没有电的概率以及不由父亲节点供电的概率。

    (g[u] = (1 - p[u])prod (g[v] + (1 - g[v]) * (1 - w(u, v))]))

    其中(v) 为 (u) 的子节点,(w(u, v)) 为 (u, v) 边有电的概率

      利用这个递推式我们可以dfs一遍自下而上获取所有节点的 (g[u]);

      然后考虑如何求得 (f[u])。要注意由于 (f[u]) 是 (u) 的父亲不供电给 (u) 的概率,所以在利用父亲的信息时应该要除去儿子的影响:

    父亲 (F) 没有电的概率 (P = f[F] * frac{g[F]}{g[u] + (1 - g[u]) * (1 - w(F, u)))} )

    父亲不供电给儿子的概率为 :

    (f[u] = P + (1 - P) * (1 - w(F, u)))

      这样就解决啦~(代码中的 (f, g) 与上述描述相反,早期代码请勿介意……)

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 505000
    #define db double
    #define eps 0.0000001
    
    int n, cnp = 1;
    int head[maxn];
    db ans, p[maxn], f[maxn], g[maxn];
    
    struct edge
    {
        int to, last; db co;
    }E[maxn * 2];
    
    void add(int u, int v, db w)
    {
        E[cnp].to = v, E[cnp].co = w;
        E[cnp].last = head[u], head[u] = cnp ++;
    }
    
    bool check(db x) { return abs(x - 0.0) < eps; }
    
    void dfs(int u, int fa)
    {
        f[u] = 1.0;
        for(int i = head[u]; i; i = E[i].last)
        {
            int v = E[i].to;
            if(v == fa) continue;
            dfs(v, u);
            f[u] *= f[v] + (1.0 - f[v]) * (1.0 - E[i].co);
        } 
        f[u] *= (1.0 - p[u]);
    } 
    
    void dfs2(int u, int fa)
    {
        for(int i = head[u]; i; i = E[i].last)
        {
            int v = E[i].to;
            if(v == fa) continue;
            db P = g[u] * f[u] / (f[v] + (1.0 - f[v]) * (1.0 - E[i].co));
            g[v] = P + (1.0 - P) * (1.0 - E[i].co);
            dfs2(v, u);
        }
        ans += 1.0 - (g[u] * f[u]);
    }
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i < n; i ++)
        {
            int a, b, p;
            scanf("%d%d%d", &a, &b, &p);
            add(a, b, (db) p / 100.0);
            add(b, a, (db) p / 100.0);
        }
        for(int i = 1; i <= n; i ++) scanf("%lf", &p[i]), p[i] /= 100.0;
        g[1] = 1.0;
        dfs(1, 0); dfs2(1, 0);
        printf("%.6lf
    ", ans);
        return 0;
    }

     

  • 相关阅读:
    多线程中static对象
    DPDK l2fwd 浅注
    DPDK编译步骤
    什么是API,SDK和API之间的关系
    linux创建定时任务发送钉钉通知
    python-webdriver中添加cookie,解决添加了图片验证码的问题
    win7下CodeIgniter安装
    XAMPP环境搭建及同类推荐
    Fiddler死活抓不了HTTPS包解决办法
    XSS注入常用语句积累
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9343716.html
Copyright © 2011-2022 走看看