[SHOI2014]概率充电器
题目
著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!
”
SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?INPUT
第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的
充电元件,通电概率为 p%。
第 n+2 行 n 个整数:qi。表示 i 号元件直接充电的概率为 qi%。OUTPUT
输出一行一个实数,为进入充电状态的元件个数的期望,四舍五入到六位小数
SAMPLE
INPUT
3
1 2 50
1 3 50
50 0 0
OUTPUT
1.000000
解题报告
mmp充个电还得看脸
首先,我们考虑,假如我们直接求每个点被充上电的期望,我们可以直接$DFS$解决,然后儿子上推???
还是太年轻~(too young too simple)
我们发现,这里不光是儿子影响父亲,同时父亲还会影响儿子,所以肯定不能傻傻的直接搞
那么我们咋搞呢?
我们发现,如果算每个点充上电的期望的话,需要求它自己直接充上电的和别人充上电传给他的,然后他自己又能给别人充电,这样就很迷
但是,假如我们可以求出每个点不被充上电的概率呢?
当它没有被充上电,那么,从它开始就断开了,不会继续下传下去,所以不会像刚才那么一直乱传那样迷
设$p[i]$为第$i$个点直接被充上电的概率,$w$为边权
设$f[i][0]$代表从$i$的子树没有把电传上来的概率
那么,$f[i][0]=(1-p[i])\times \prod_{j\in son[i]}(f[j][0]+(1-f[j][0])\times (1-w))$
即:该点没有从儿子那里传上来的概率=所有子树没有的概率+子树有的概率*路径没传过来的概率
设$f[i][1]$代表从$i$的父亲没有把电传下来的概率,$t$为其他点传到父亲失败的概率
$$t=\frac{f[fa][0]}{f[i][0]+(1-f[i][0])\times (1-w)}\times f[fa][1]$$
$$f[i][1]=t+(1-t)\times (1-w)$$
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6 int sum(0); 7 char ch(getchar()); 8 for(;ch<‘0‘||ch>‘9‘;ch=getchar()); 9 for(;ch>=‘0‘&&ch<=‘9‘;sum=sum*10+(ch^48),ch=getchar()); 10 return sum; 11 } 12 struct edge{ 13 int e; 14 double w; 15 edge *n; 16 }a[1000005],*pre[500005]; 17 int tot; 18 inline void insert(int s,int e,int w){ 19 a[++tot].e=e; 20 a[tot].w=w/100.0; 21 a[tot].n=pre[s]; 22 pre[s]=&a[tot]; 23 } 24 int n; 25 int fa[500005]; 26 double p,f[500005][2]; 27 inline void dfs1(int u){ 28 for(edge *i=pre[u];i;i=i->n){ 29 int e(i->e); 30 if(e!=fa[u]){ 31 fa[e]=u; 32 dfs1(e); 33 f[u][0]*=f[e][0]+(1.0-f[e][0])*(1.0-i->w); 34 } 35 } 36 } 37 inline void dfs2(int u){ 38 for(edge *i=pre[u];i;i=i->n){ 39 int e(i->e); 40 if(e!=fa[u]){ 41 double tmp(f[u][0]/(f[e][0]+(1.0-f[e][0])*(1.0-i->w))*f[u][1]); 42 f[e][1]=tmp+(1.0-tmp)*(1.0-i->w); 43 dfs2(e); 44 } 45 } 46 } 47 int main(){ 48 memset(pre,NULL,sizeof(pre)); 49 n=read(); 50 for(int i=1;i<n;++i){ 51 int x(read()),y(read()),z(read()); 52 insert(x,y,z),insert(y,x,z); 53 } 54 for(int i=1;i<=n;++i){ 55 p=read(); 56 f[i][0]=1.0-p/100.0; 57 } 58 dfs1(1); 59 f[1][1]=1; 60 dfs2(1); 61 double ans(0); 62 for(int i=1;i<=n;++i) 63 ans+=1.0-f[i][0]*f[i][1]; 64 printf("%lf",ans); 65 }