BZOJ3566: [SHOI2014]概率充电器(概率DP+容斥)

传送门

题意:
一棵树上每条边有连通概率,每个点有通电概率,点的通电可以通过边传递,求期望通电的点的次数。

题解:
好题啊。。

首先由期望的线性性可以知道答案就是每个点连通的概率相加。

现在考虑如何求概率。
首先,以任意点为根节点DP可以得出仅考虑一个点的子树这个点的连通概率。考虑怎么统计父节点。

因为是从根节点向下更新,而根节点的连通概率已经知道,可以假设现在父节点的连通概率是已知的。

由概率公式

P(A+B)=P(A)+P(B)P(A)P(B)

已知父亲通电概率 P(A+B) ,儿子向父亲传送电的概率 P(B) ,父亲不通过该儿子也可以通电的概率 P(A) 可以求出,那么儿子再用概率加法加上父节点给儿子通电的概率就好了。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
}
typedef pair<int,int> pii;
const int Maxn=5e5+50;
const double eps=1e-9;
double dp[Maxn][3];
int n,P[Maxn];
vector<pii>edge[Maxn];
inline void dfs(int now,int f){
    double sum_not_ok=1.0;dp[now][0]=1.0;
    for(int e=edge[now].size()-1;e>=0;e--){
        int v=edge[now][e].first,w=edge[now][e].second;
        if(v==f)continue;
        dfs(v,now);
        double p_edge=(double)w/100.0;
        double t=p_edge*dp[v][0]+(1-p_edge)*(dp[v][0]+dp[v][1]);
        dp[now][0]*=t;
    }
    double p_now=(double)P[now]/100.0;
    dp[now][0]=dp[now][0]*(1.0-p_now);
    dp[now][1]=1.0-dp[now][0];
}
inline void dfs2(int now,int f){
    double p_now=(double)P[now]/100;
    for(int e=edge[now].size()-1;e>=0;e--){
        int v=edge[now][e].first,w=edge[now][e].second;
        if(v==f)continue;
        double p_edge=(double)w/100.0;
        double t=dp[v][1]*p_edge;
        if(1-t<eps)t=0; 
        else t=(dp[now][1]-t)/(1-t);
        dp[v][1]=dp[v][1]+t*p_edge-dp[v][1]*t*p_edge;
        dfs2(v,now);
    }
}
int main(){
    n=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read(),w=read();
        edge[x].push_back(make_pair(y,w));
        edge[y].push_back(make_pair(x,w)); 
    }
    for(int i=1;i<=n;i++)P[i]=read();
    dfs(1,0);
    dfs2(1,0);
    double ans=0;
    for(int i=1;i<=n;i++)
        ans+=dp[i][1];
    printf("%.6f",ans);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值