您的位置:首页 > 其它

Bzoj3566:[SHOI2014]概率充电器:概率dp

2016-06-12 21:21 375 查看
题目链接[SHOI2014]概率充电器

woc我的高考概率是怎么学的这么简单的概率公都忘了233

公式:设事件A,B,p为概率,则

p(A|B)=p(A)+p(B)-p(A&B)

意思是发生A或B事件之一的概率是发生A的概率+发生B的概率-A和B同时发生概率

那么一个点x有电的情况为1:自己给自己充上了电;2:子节点给他充上了电;3:父节点给他充上了电

设事件1的概率为p[x],那么1、2使得x有电的概率可以直接使用公式dfs求出来

现在考虑3,我们从父节点贡献到子节点时要把子节点贡献给父节点的贡献减去,公式变一下形即可算出

然后在正向用公式合并即可

注意除法的时候判断除数大小,被坑了

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500010;
int n,m,tot=1,h[maxn];
struct edge{int to,next; double w;}G[maxn*2];
double p[maxn],dp[maxn];

void dfs1(int x,int fat){
for (int i=h[x];i;i=G[i].next){
int v=G[i].to;
if (v==fat) continue;
dfs1(v,x);
p[x]=p[x]+p[v]*G[i].w-p[x]*p[v]*G[i].w;//p(A|B)=p(A)+p(B)-p(A&B);
}
}

void dfs2(int x,int fat){
for (int i=h[x];i;i=G[i].next){
int v=G[i].to;
if (v==fat) continue;
double tmp=1-p[v]*G[i].w;
if (abs(tmp)<1e-10) dp[v]=1;//这里要注意
else{
double tmp2=(dp[x]-p[v]*G[i].w)/tmp;
dp[v]=p[v]+tmp2*G[i].w-p[v]*tmp2*G[i].w;
}
dfs2(v,x);
}
}

void add(int x,int y,double z){
G[++tot].to=y;G[tot].next=h[x];h[x]=tot;G[tot].w=z;
G[++tot].to=x;G[tot].next=h[y];h[y]=tot;G[tot].w=z;
}

int main(){
scanf("%d",&n);
for (int i=1;i<n;++i){
int x,y; double z;
scanf("%d%d%lf",&x,&y,&z);
z/=100.0; add(x,y,z);
}
for (int i=1;i<=n;++i) scanf("%lf",&p[i]),p[i]/=100.0;
dfs1(1,-1); dp[1]=p[1]; dfs2(1,-1);
double ans=0;
for (int i=1;i<=n;++i) ans+=dp[i];
printf("%.6lf",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BZOJ 概率与期望 dp