说在前面
并没有什么想说的,但是要保持格式=w=
(肚子疼得1B…简直有毒)
题目
BZOJ3566传送门
不是权限题
看题可进传送门
解法
首先要知道这几个公式(A,B独立,发生条件互不影响):
P(A⋂B)=P(A)∗P(B)
P
(
A
⋂
B
)
=
P
(
A
)
∗
P
(
B
)
意思是:A和B同时发生的概率,等于A,B发生概率的乘积
P(A⋃B)=P(A)+P(B)−P(A⋂B)
P
(
A
⋃
B
)
=
P
(
A
)
+
P
(
B
)
−
P
(
A
⋂
B
)
意思是:A和B至少有一个发生的概率,等于A发生的概率+B发生的概率 - A,B同时发生的概率
P(A)=P(A⋃B)−P(B)1−P(B)
P
(
A
)
=
P
(
A
⋃
B
)
−
P
(
B
)
1
−
P
(
B
)
这个式子可以直接由上面那个推导得到
可以这么理解:A发生的概率,等于(在B不发生时,A发生的概率)除以(B不发生的概率)
然后就可以开始做题了,分开讨论子树和父亲对 当前节点 的贡献。
先dfs一遍,求出每个节点依靠自身或子树通电的概率。这样可以得到根节点通电的概率,因为根节点要么本身有电,要么靠儿子导电,这两个概率是独立的(不会出现 根节点先有电,然后导电给儿子,儿子再导电给自己 的情况),可以类似的推广下去,所以这样求是正确的
然后再dfs一遍,求出 当前节点 被父亲节点通电的概率。用上面的第三个公式,可以得到(父节点不受当前节点影响而通电的概率)。结合第一次dfs的信息,就可以求出当前节点通电的概率
下面是自带大常数的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const double eps = 1e-9 ;
int N , tp , head[500005] ;
struct Path{
int pre , to ;
double prob ;
} p[1000005] ;
void In( int &t1 , int &t2 , double t3 ){
p[++tp] = ( Path ){ head[t1] , t2 , t3 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 , t3 } ; head[t2] = tp ;
}
int cmp( double x ){
if( x < eps && x > -eps ) return 0 ;
return x > eps ? 1 : -1 ;
}
double Merge( double x , double y ){ return x + y - x * y ; }
double Split( double x , double y ){ return cmp( 1 - y ) == 0 ? 1 : ( x - y ) / ( 1.0 - y ) ; }
double Light_sub[500005] , Light_fa[500005] , Light[500005] , ans ;//sub = subtree
void dfs1( int u , int f ){
double &now = Light_sub[u] /= 100 ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
dfs1( v , u ) ;
now = Merge( now , Light_sub[v] * p[i].prob ) ;
}
}
void dfs2( int u , int f ){
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
Light_fa[v] = p[i].prob * Split( Light[u] , Light_sub[v] * p[i].prob ) ;
ans += ( Light[v] = Merge( Light_fa[v] , Light_sub[v] ) ) ;
dfs2( v , u ) ;
}
}
void solve(){
dfs1( 1 , 1 ) ;
ans += ( Light[1] = Light_sub[1] ) ;
dfs2( 1 , 1 ) ;
printf( "%.6f\n" , ans ) ;
}
int main(){
scanf( "%d" , &N ) ;
for( int i = 1 , u , v ; i < N ; i ++ ){
double prob ;
scanf( "%d%d%lf" , &u , &v , &prob ) ;
In( u , v , prob/100 ) ;
}
for( int i = 1 ; i <= N ; i ++ )
scanf( "%lf" , &Light_sub[i] ) ;
solve() ;
}