Bzoj3566/洛谷P4284 [SHOI2014]機率充電器(機率dp)

題面

Bzojphp

洛谷code

題解

首先考慮從兒子來的貢獻:get

$$ f[u]=\prod_{v \in son[u]}f[v]+(1-f[v])\times(1-dis[i]) $$string

根據容斥原理,就是兒子直接亮的機率減去當兒子不亮且他們之間的路徑均不直接亮時的機率it

接着考慮從父親來的貢獻,設$p$爲:$\frac{g[u]\times f[u]}{f[v]+(1-f[v])\times(1-dis[i])}$io

則:(畫畫圖就能夠理解)class

$$ g[v]=p+(1-p)\times(1-dis[i]) $$原理

最後答案就是im

$$ \sum_{i=1}^n1-f[i]\times g[i] $$sort

#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;
}
相關文章
相關標籤/搜索