Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 1276 Solved: 558
Description
著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!
”
SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?
Input
第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的
充电元件,通电概率为 p%。
第 n+2 行 n 个整数:qi。表示 i 号元件直接充电的概率为 qi%。
Output
输出一行一个实数,为进入充电状态的元件个数的期望,四舍五入到六位小数
Sample Input
3
1 2 50
1 3 50
50 0 0
Sample Output
1.000000
HINT
对于 100%的数据,n≤500000,0≤p,qi≤100。
Source
By 佚名提供
这题好难啊…真的搞了好长时间才搞懂,网上题解貌似也都不是特别地清真,除了有两份还比较清晰的,以下是一份,如果我的看不懂可以去看这篇dalao讲解
首先我们定义几个东西
f[i]
表示由它的整个子树给他供不上电的概率(这个里面包括了自己不来电的情况,因为自己也算在自己所在的子树中,也包含了所有的孩子不给他供电的情况,利用乘法原理计算)
g[i]
表示由他的父亲不能给他供上电的概率
显然第
i
个点不被供电的概率是
显然我们可以发现光是定义一个 f[i] 和 g[i] 不是很容易转移,两者之间貌似也没有太大的联系可以直接去转移,于是我们再定义一个数组 h[i]
h[i]
表示i点对其父亲充不上电的贡献,换句话说,表示i点不能给他父亲供电的概率
那么显然有
其中
p
表示
则显然
而对于叶节点,显然叶节点的
f
值就等于自己不来电的概率,
对
f[i]
的求解,显然应该有
这里的 p[i] 表示 i 自来电的概率
那么最后一个问题是求解
我们对于
g[v]
的求解,令
u
为他的父亲,则定义一个变量为
最后
这里的 p 表示和父亲连的边的通电几率
我们先看前面这个,如果
比如下面这幅图就表现了这种无法
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 500000 + 10;
int head[MAXN], tail, fa[MAXN];
double f[MAXN], h[MAXN], g[MAXN];
struct Line{ int to, nxt; double p; }line[ MAXN * 2 ];
void add_line( int from, int to, double p ) {
line[++tail].nxt = head[from];
head[from] = tail;
line[tail].to = to;
line[tail].p = p;
}
void dfs1( int u, int fat ) {
fa[u] = fat;
for( register int i = head[u]; i; i = line[i].nxt ) {
int v = line[i].to;
if( v == fat ) continue;
dfs1( v, u );
h[v] = f[v] + ( 1 - f[v] ) * ( 1.0 - line[i].p );
f[u] *= h[v];
}
}
void dfs2( int u, int fat ) {
for( register int i = head[u]; i; i = line[i].nxt ) {
int v = line[i].to;
if( v == fat ) continue;
double t = h[v] < 1e-6 ? 0 : g[u] * f[u] / h[v];
g[v] = t + ( 1.0 - t ) * ( 1.0 - line[i].p );
dfs2( v, u );
}
}
int main( ) { int n;
scanf( "%d", &n ); int ff, tt, pp;
for( register int i = 1; i <= n - 1; i++ ) {
scanf( "%d%d%d", &ff, &tt, &pp );
add_line( ff, tt, pp / 100.0 );
add_line( tt, ff, pp / 100.0 );
}
for( register int i = 1; i <= n; i++ ) { int tmp;
scanf( "%d", &tmp );
f[i] = 1.0 - tmp / 100.0;
}
dfs1( 1, 0 );
g[1] = 1.0;
dfs2( 1, 0 );
double ans = 0.0;
for( register int i = 1; i <= n; i++ ) ans += 1.0 - f[i] * g[i];
printf( "%.6lf\n", ans );
return 0;
}