Bzoj3566/洛谷P4284 [SHOI2014]概率充电器(概率dp)

题面

Bzoj

洛谷

题解

首先考虑从儿子来的贡献:

根据容斥原理,就是儿子直接亮的概率减去当儿子不亮且他们之间的路径均不直接亮时的概率

接着考虑从父亲来的贡献,设$p$为:$\frac{g[u]\times f[u]}{f[v]+(1-f[v])\times(1-dis[i])}$

则:(画画图就可以理解)

最后答案就是

#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
typedef long long ll;
typedef double db;

template<typename T>
void read(T &x) {
    int flag = 1; x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
    while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}

const int N = 5e5 + 10;
db poi[N], ret, son[N], fa[N], dis[N << 1];
int n, to[N << 1], nxt[N << 1], from[N], cnt;
bool vis[N];
inline void addEdge(int u, int v, db w) {
    to[++cnt] = v, nxt[cnt] = from[u], dis[cnt] = w, from[u] = cnt;
}

void dfs1(int u) {
    vis[u] = 1, son[u] = 1. - poi[u];
    for(int i = from[u]; i; i = nxt[i]) {
        int v = to[i]; if(vis[v]) continue; dfs1(v);
        son[u] *= son[v] + (1. - son[v]) * (1. - dis[i]);
    } vis[u] = 0;
}

void dfs2(int u) {
    vis[u] = 1;
    for(int i = from[u]; i; i = nxt[i]) {
        int v = to[i]; if(vis[v]) continue;
        db p = fa[u] * son[u] / (son[v] + (1. - son[v]) * (1. - dis[i]));
        fa[v] = p + (1. - p) * (1. - dis[i]); dfs2(v);
    }
}

int main () {
    read(n);
    for(int i = 1, u, v, w; i < n; ++i)
        read(u), read(v), read(w), addEdge(u, v, w / 100.), addEdge(v, u, w / 100.);
    for(int i = 1, p; i <= n; ++i)
        read(p), poi[i] = p / 100.;
    fa[1] = 1, dfs1(1), dfs2(1);
    for(int i = 1; i <= n; ++i)
        ret += 1. - fa[i] * son[i];
    return printf("%.6lf\n", ret) & 0;
}