这是一道概率+树形\(dp\)

首先我们看到这里每一个的贡献都是1,所以我们要求的期望就是概率

求得其实就是这个

\[\sum_{i=1}^nP_i
\]

\(P_i\)为节点\(i\)通电的概率

显然节点\(i\)通电有三种可能

  1. 它自己来电了

  2. 它的子树里有一个点来电了传了过来

  3. 它的子树外面有一个点来电了传了过来

第一种情况最好考虑了,至于第二种和第三种我们好像很难解决的样子

但是这显然也告诉了我们这是一个套路题,第二种和第三种正好就是树规里的\(up\) \(and\) \(down\)思想

于是我们设\(h[i]\)表示第\(i\)个节点通电的概率,之后我们利用\(up\) \(and\) \(down\)思想,在第一遍dfs的过程中,\(h[i]\)表示\(i\)通电的概率,且电一定来自它自己或者它的子树里(对应第一第二种情况),在第二遍dfs的时候被更新成为电来自于任何地方的概率(对应所有情况)

最开始初始化,\(h[i]=a[i]*0.01\)电只能来自自己

之后第一遍dfs,树形dp里的\(up\),我们要将子树的信息合并给根,由于根通电还是有两种可能

  1. 根自己来电了

  2. 儿子来电,儿子通向根的边导电

显然这两种情况只需要满足一种就够了

但是合并之后的概率是多少呢,直接加起来显然是不对的而我还真加了起来

我们考虑有两个事件\(A,B\),发生的概率分别是\(P(A),P(B)\),那么至少发生一件的概率应该是

\[P(A)+P(B)-P(A)*P(B)
\]

这个怎么推出来的,很简单,至少发生一件,那么就有三种可能

  1. \(A\)发生\(B\)不发生,那么则为\(P(A)*(1-P(B))\)

  2. \(B\)发生\(A\)不发生,那么则为\(P(B)*(1-P(A))\)

  3. \(A,B\)一起发生,那么则为\(P(A)*P(B)\)

三项合起来最后一化就是\(P(A)+P(B)-P(A)*P(B)\)

所以我们合并根和子树的信息的时候,\(P(A)=h[i],P(B)=h[j]*p(i,j)\),\(i\)是子树的根,\(j\)是\(i\)的儿子,\(p(i,j)\)是这条边导电的概率

所以\(h[i]=P(A)+P(B)-P(A)*P(B)\)

之后我们就要考虑\(down\)了,一个节点有点也有可能来自它的父亲,于是我们采用\(down\)的思想用父亲更新儿子

显然我们更新一位父亲的某个儿子,显然我们只能用其他点来电传到父亲的概率来更新这个儿子

于是我们设\(P(B)=h[j]*p(i,j)\),而且有

\[P(A)+P(B)-P(A)*P(B)=h[i]
\]

我们要求的是\(P(A)\)即除了\(j\)这棵子树其他点来电使得\(i\)有电的概率

于是解一下这个方程

\[P(A)-P(A)*P(B)=h[i]-P(B)
\]

\[P(A)*(1-P(B))=h[i]-P(B)
\]

\[P(A)=\frac{h[i]-P(B)}{1-P(B)}
\]

而之后我们去更新儿子的话还有一边是否导电需要考虑,于是

\[h[j]=h[j]+(P(A)*p(i,j))-h[j]*P(A)*p(i,j)
\]

之后就没有啦,同时还有一个非常坑的地方就是如果\(P(B)=h[j]*p(i,j)=1\)

那么除以\(1-P(B)\)肯定会出错,由于\(h[j]\)都已经是1了,显然没有什么必要去更新它了,于是可以直接跳过这一层接着往下更新就好了

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 500005
#define eps 1e-7
struct node
{
int v,nxt,w;
}e[maxn<<1];
int num,n,m;
int a[maxn],head[maxn],deep[maxn];
double h[maxn];
double ans;
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
inline void add_edge(int x,int y,int z)
{
e[++num].v=y;
e[num].nxt=head[x];
e[num].w=z;
head[x]=num;
}
void dfs(int x)//up
{
for(re int i=head[x];i;i=e[i].nxt)
if(!deep[e[i].v])
{
deep[e[i].v]=deep[x]+1;
dfs(e[i].v);
double k=h[e[i].v]*double(e[i].w)/100;
h[x]=h[x]+k-h[x]*k;
}
}
inline int check(double aa,double bb)
{
if(aa+eps>bb&&aa-eps<bb) return 1;
return 0;
}
void redfs(int x)//down
{
ans+=h[x];
for(re int i=head[x];i;i=e[i].nxt)
if(deep[e[i].v]>deep[x])
{
if(check(h[e[i].v]*double(e[i].w)/100,1))
{
redfs(e[i].v);
continue;
}
double k=(h[x]-h[e[i].v]*double(e[i].w)/100)/(1-h[e[i].v]*double(e[i].w)/100);
k*=double(e[i].w)/100;
h[e[i].v]=h[e[i].v]+k-k*h[e[i].v];
redfs(e[i].v);
}
}
int main()
{
n=read();
int x,y,z;
for(re int i=1;i<n;i++)
{
x=read();
y=read();
z=read();
add_edge(x,y,z),add_edge(y,x,z);
}
for(re int i=1;i<=n;i++)
a[i]=read(),h[i]=a[i]*0.01;
deep[1]=1;
dfs(1);
redfs(1);
printf("%.6lf",ans);
return 0;
}

【[SHOI2014]概率充电器】的更多相关文章

  1. BZOJ 3566: [SHOI2014]概率充电器( 树形dp )

    通过一次dfs求出dp(x)表示节点x考虑了x和x的子树都没成功充电的概率, dp(x) = (1-p[x])π(1 - (1-dp[son])*P(edge(x, son)).然后再dfs一次考虑节 ...

  2. BZOJ 3566: [SHOI2014]概率充电器 [树形DP 概率]

    3566: [SHOI2014]概率充电器 题意:一棵树,每个点\(q[i]\)的概率直接充电,每条边\(p[i]\)的概率导电,电可以沿边传递使其他点间接充电.求进入充电状态的点期望个数 糖教题解传 ...

  3. BZOJ3566: [SHOI2014]概率充电器 树形+概率dp

    3566: [SHOI2014]概率充电器 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1888  Solved: 857[Submit][Stat ...

  4. 洛谷 P4284 [SHOI2014]概率充电器 解题报告

    P4284 [SHOI2014]概率充电器 题目描述 著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品-- 概率充电器: "采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  5. P4284 [SHOI2014]概率充电器

    P4284 [SHOI2014]概率充电器 今天上课讲到的题orz,第一次做这种上下搞两次dp的题. g[i]表示i的子树(包括i)不给i充电的概率. f[i]表示i的父亲不给i充电的概率. g[]可 ...

  6. 【BZOJ 3566】 3566: [SHOI2014]概率充电器 (概率树形DP)

    3566: [SHOI2014]概率充电器 Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:“采用全新纳米级加工技术,实现元件与导线能否通电 ...

  7. BZOJ3566 SHOI2014 概率充电器 【概率DP】

    BZOJ3566 SHOI2014 概率充电器 Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器: “采用全新纳米级加工技术,实现元件与导线能 ...

  8. 【BZOJ3566】[SHOI2014]概率充电器 期望+树形DP

    [BZOJ3566][SHOI2014]概率充电器 Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:“采用全新纳米级加工技术,实现元件与导线 ...

  9. BZOJ_3566_[SHOI2014]概率充电器_概率+树形DP

    BZOJ_3566_[SHOI2014]概率充电器_概率+树形DP Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器: “采用全新纳米级加工技 ...

  10. BZOJ3566 [SHOI2014]概率充电器 (树形DP&概率DP)

    3566: [SHOI2014]概率充电器 Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:“采用全新纳米级加工技术,实现元件与导线能否通电 ...

随机推荐

  1. SpringBoot和SpringCloud区别

    SpringBoot专注于快速方便的开发单个个体微服务.    SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,    为各个服 ...

  2. ngnix优化【转】

    nginx的优化 1. gzip压缩优化 2. expires缓存有还 3. 网络IO事件模型优化 4. 隐藏软件名称和版本号 5. 防盗链优化 6. 禁止恶意域名解析 7. 禁止通过IP地址访问网站 ...

  3. getElementsByName属性

    getElementsByName() 方法可返回带有指定名称的对象的集合 语法 document.getElementsByName(name) 该方法与 getElementById() 方法相似 ...

  4. python __new__()分析

    我们来看下下面类中对__new__()方法的实现: class Demo(object): def __init__(self): print '__init__() called...' def _ ...

  5. Redis 常见命令

    0. 5种数据类型 String(字符串) List(列表) Hash(字典) Set(集合) Sorted Set(有序集合) 1. String 字符串 set key value 设置key=v ...

  6. 两种实现光标点插入range

    一.insertNode <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  7. div 居中方法汇总

    本文是从简书复制的, markdown语法可能有些出入, 想看"正版"和更多内容请关注 简书: 小贤笔记 情况一: 父子容器宽高已知 方法一 html <div class= ...

  8. C++类继承--基类new和用派生类new的区别

    实际上无论是用基类还是派生类New, 结果是一样的: #include <stdio.h> class Base { public: int a; Base(){ a=0; } virtu ...

  9. 【JAVA语法】01Java-变量与数据类型

    数据类型初阶 基本数据类型的包装类 整数类型&浮点类型&字符类型 大小类型转换 通过Scanner从控制台获取数据 变量相关基础算法 Java的错误类型 字符串String 补充-Pa ...

  10. Android Studio修改app图标

    1.将下载好的图片放到app\src\main\res\drawable目录下 2.在AndroidManifest.xml下加入一句 android:icon="@drawable/??? ...