BZOJ-3566: [SHOI2014]概率充电器(树形DP)

作者: AmadeusChan | 来源:发表于2019-02-16 20:08 被阅读0次

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3566

树形DP,设up[ v ]为在v的子树中,v的充电概率,设dp[ v ]为在整颗树中v的充电概率,那么:

令merge( x , y ) = x + y - x * y(容斥原理)

up[ v ] = merge( up[ v ] , up[ child( v ) ] * e( v , child( v ) ) )

然后,dp[ root ] = up[ root ],对于一条边(v , u),若v为父亲,dp[ v ]已知,那么dp[ u ]为:

当1 - up[ u ] * e( u , v ) = 0时,dp[ u ] = 1 , 否则 dp[ u ] = merge( up[ u ] , ( dp[ v ] - up[ u ] * e( u , v ) ) / ( 1 - up[ u ] * e( u , v ) ) * e( u , v ) )。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
 
using namespace std ;
 
#define travel( x ) for ( vector < edge > :: iterator p = E[ x ].begin(  ) ; p != E[ x ].end(  ) ; ++ p )
#define rep( i , x ) for ( int i = 0 ; i ++ < x ; )
 
#define addedge( s , t , p ) add( s , t , p ) , add( t , s , p )
#define add( s , t , p ) E[ s ].push_back( edge( t , p ) )
 
const int maxn = 501000 ;
const double esp = 0.00000001 ;
 
struct edge {
    int t ;
    double p ; 
    edge( int _t , double _p ) : t( _t ) , p( _p ) {
    }
} ;
vector < edge > E[ maxn ] ;
 
int n ; 
double q[ maxn ] ;
 
double up[ maxn ] , dp[ maxn ] ;
 
double merge( double x , double y ) {
    return x + y - x * y ;
}
 
void dfs_up( int now , int fa ) {
    up[ now ] = q[ now ] ;
    travel( now ) if ( p -> t != fa ) {
        dfs_up( p -> t , now ) ;
        up[ now ] = merge( up[ now ] , up[ p -> t ] * p -> p ) ;
    }
}
 
void dfs_dp( int now , int fa ) {
    double rec , ret ; 
    travel( now ) if ( p -> t != fa ) {
        if ( ( 1 - ( rec = p -> p * up[ p -> t ] ) ) > esp ) {
            ret = ( dp[ now ] - rec ) / ( 1 - rec ) ;
            dp[ p -> t ] = merge( up[ p -> t ] , ret * p -> p ) ;
        } else dp[ p -> t ] = 1.0 ;
        dfs_dp( p -> t , now ) ;
    }
}
 
int main(  ) {
    scanf( "%d" , &n ) ;
    rep( i , ( n - 1 ) ) {
        int s , t ; double p ; scanf( "%d%d%lf" , &s , &t , &p ) ;
        p = p / 100.0 ;
        addedge( s , t , p ) ;
    }
    rep( i , n ) {
        scanf( "%lf" , q + i ) ;
        q[ i ] = q[ i ] / 100.0 ;
    }
    dfs_up( 1 , 0 ) ;
    dp[ 1 ] = up[ 1 ] ;
    dfs_dp( 1 , 0 ) ;
    double ans = 0 ;
    rep( i , n ) ans += dp[ i ] ;
    printf( "%.6f\n" , ans ) ;
    return 0 ; 
}

相关文章

  • BZOJ-3566: [SHOI2014]概率充电器(树形DP)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3566 树...

  • AcWing 285. 没有上司的舞会

    AcWing 285. 没有上司的舞会 树形dp 从小偷系列问题演变过来的树形dp问题

  • 树形DP

    树形dp的模板是在做题中总结出来的 POJ 2342 Anniversary party_边 树形DP满足自下而上...

  • 树形DP

    求树上最长链(或者说树的直径、树上距离最远的两点距离,树中所有最短路径距离的最大值) 1.树形DP(可以有效处理负...

  • DP训练——树形DP

    树形DP BZOJ4472[https://www.lydsy.com/JudgeOnline/problem.p...

  • DP小结

    DP种类 线性DP 区间DP 树形DP 背包DP01背包满背包完全背包(转成01背包) 例子:线性动规:拦截导弹,...

  • 树形DP 选课

    树上的背包问题 学校实行学分制。每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。学校开设了N(N<3...

  • 概率DP

    http://codeforces.com/problemset/problem/148/D 递归超时版本

  • 概率DP

    http://blog.csdn.net/just_sort/article/details/51500004ht...

  • 1519. 子树中标签相同的节点数

    1519. 子树中标签相同的节点数 树形dp

网友评论

    本文标题:BZOJ-3566: [SHOI2014]概率充电器(树形DP)

    本文链接:https://www.haomeiwen.com/subject/plvieqtx.html