正题
luogu 4284
题目大意
给你棵树,第i个点自己通电的概率是wiw_iwi,第j条边连接的两个点之间通电的概率是pjp_jpj,问你通电的点个数的期望值
题目大意
设fif_ifi为第i个点通电的概率,那么:
fi=solvej∈link{i}(fi,fj∗pj)f_i=solve_{j\in link\{i\}}(f_i, f_j*p_j)fi=solvej∈link{i}(fi,fj∗pj)
即从该点转一过来,fif_ifi初值为wiw_iwi,solve为合并两个概率
假设有x,y的概率由不同的两个方法通电,那么p=1-(1-x)(1-y)=x+y-xy,即是solve
可以先按上述方法向父亲转移,计算出子节点传递到x的贡献
.
然后可以再从根节点向下计算父亲向x的贡献,但是要减去该点传到父亲再传回去的概率,记不是由x传递过来,fa通电的概率为p,该点传到父亲的贡献为g,那么有:
p+g−pg=ffap+g-pg=f_{fa}p+g−pg=ffa
p(1−g)=ffa−gp(1-g)=f_{fa}-gp(1−g)=ffa−g
p=ffa−g1−gp=\frac{f_{fa}-g}{1-g}p=1−gffa−g
这样就可以得到其贡献了
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 500050
using namespace std;
int n, x, y, tot, h[N], fa[N], deg[N];
double z, ans, g[N], f[N];
queue<int>d;
struct rec
{int to, next;double p;
}e[N<<1];
int read()
{char x=getchar();int ds=0,fs=1;while (x<'0'||x>'9') {if (x=='-') fs=-1;x=getchar();}while (x>='0'&&x<='9') ds=(ds<<3)+(ds<<1)+x-48,x=getchar();return ds*fs;
}
void add(int x, int y, double z)
{e[++tot].to = y;e[tot].p = z;e[tot].next = h[x];h[x] = tot;return;
}
double get(double x, double y)//计算
{return x + y - x * y;
}
void bfs()
{d.push(1);while(!d.empty()){int x = d.front();d.pop();for (int i = h[x]; i; i = e[i].next){int v = e[i].to;if (v != fa[x]){fa[v] = x;deg[v]--;d.push(v);}}}
}
void bfs1()
{for (int i = 1; i <= n; ++i)if (!deg[i])d.push(i);while(!d.empty()){int x = d.front();d.pop();if (!--deg[fa[x]]) d.push(fa[x]);for (int i = h[x]; i; i = e[i].next){int y = e[i].to;if (y != fa[x]){g[y] = f[y] * e[i].p;//从下向上传f[x] = get(f[x], g[y]);}}}return;
}
void bfs2()
{d.push(1);while(!d.empty()){int x = d.front();d.pop();for (int i = h[x]; i; i = e[i].next){int y = e[i].to;if (y != fa[x]){if (g[y] < 1.0) f[y] = get(f[y], ((f[x] - g[y]) / (1 - g[y])) * e[i].p);//从上到下传,保证分母不为0d.push(y);}}}
}
/*
void dfs1(int x, int fa)//dfs会暴栈
{f[x] = f[x] / 100.0;for (int i = h[x]; i; i = e[i].next){int y = e[i].to;if (y != fa){dfs1(y, x);g[y] = f[y] * e[i].p;f[x] = get(f[x], g[y]);}}return;
}
void dfs2(int x, int fa)
{for (int i = h[x]; i; i = e[i].next){int y = e[i].to;if (y != fa){if (g[y] < 1.0) f[y] = get(f[y], ((f[x] - g[y]) / (1 - g[y])) * e[i].p);dfs2(y, x);}}return;
}
*/
int main()
{n = read();for (int i = 1; i < n; ++i){x = read();y = read();z = read() / 100.0;add(x, y, z);add(y, x, z);deg[x]++;deg[y]++;}for (int i = 1; i <= n; ++i)f[i] = read() / 100.0;bfs();bfs1();bfs2();
// dfs1(1, 0);
// dfs2(1, 0);for (int i = 1; i <= n; ++i)ans = ans + f[i];printf("%.6lf", ans);return 0;
}