概率充电器
Posted leom10
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了概率充电器相关的知识,希望对你有一定的参考价值。
3566: [SHOI2014]概率充电器
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 2065 Solved: 970
[Submit][Status][Discuss]
Description
著名的电子产品品牌 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
1 2 50
1 3 50
50 0 0
Sample Output
HINT
对于 100%的数据,n≤500000,0≤p,qi≤100。
考试经历:刚一看到这题觉得这题水的一批,当时觉得能A掉这题,结果自己连题都理解错了,当时以为电只能由父亲节点转移给子节点,然后概率的话直接乘起来就完全ojbk,然自信满满的打了个dfs,结果WA5 ,结果这5分成了我唯一一个过了的点。
好了,开始改题了
其实这题一点都不水,本人菜逼看题解还理解了半天,而且也没弄的特别明白
首先显然,这题是一个树形,然后就顺理成章的想到树dp,然而我没想到,因为计算他被点亮的概率有点困难(貌似要用到容斥什么balabala的我不会的东西),所以,正难则反,
我们可以计算他不被点亮的概率
因为每个点连通也就是权值为1,所以这道题概率与期望的值是相等的。
因为直接计算一个点连通的概率很不方便,所以我们考虑一个点不连通的概率,于是设f[x]表示x这个点不连通的概率。
先考虑xx的儿子对它的贡献,那么f[x]=(1−p[x])∗∏(1−(1−f[v])∗w),其中v为x的儿子,w为边连通的概率。
现在考虑v的父亲x对v的贡献,我们设res为x除去v这个点连通的概率,那么res=1−f[x]/(1−(1−f[v])∗w)。于是f[v]∗=1−res∗w。
两个式子,我们进行两遍dfs,即可算出f[x]。那么Ans=∑1−f[i],于是我们成功地解决了这题。
最后一点要注意的是这题会卡你精度就是在上面推出来的式子里要判断一下(不然会被卡95)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<vector> 6 #include<queue> 7 #include<algorithm> 8 const int N=2e6+10; 9 int first[N],nex[N],to[N]; 10 double edge[N]; 11 const double temp=1e-7; 12 int pp[N],qq[N],tot; 13 double p[N],q[N],f[N]; int n; 14 using namespace std; 15 inline void add(int x,int y,double z) 16 to[++tot]=y;edge[tot]=z;nex[tot]=first[x];first[x]=tot; 17 18 inline void dfs1(int x,int fa) 19 for(int i=first[x];i;i=nex[i]) 20 int y=to[i]; 21 if(y==fa) continue; 22 dfs1(y,x); 23 f[x]*=(1.0-(1.0-f[y])*edge[i]); 24 25 26 inline void dfs2(int x,int fa) 27 for(int i=first[x];i;i=nex[i]) 28 int y=to[i]; 29 if(y==fa) continue; 30 double res=0; 31 res=1.0-f[x]/(1.0-(1.0-f[y])*edge[i]); 32 33 f[y]*=(1-res*edge[i]); 34 dfs2(y,x); 35 36 37 int main() 38 39 freopen("9.in","r",stdin); 40 scanf("%d",&n); 41 for(int i=1;i<=n-1;i++) 42 int x,y; 43 scanf("%d%d%d",&x,&y,&pp[i]); 44 p[i]=pp[i]/100.0; 45 add(x,y,p[i]); 46 add(y,x,p[i]); 47 48 for(int i=1;i<=n;i++) scanf("%d",&qq[i]); 49 for(int i=1;i<=n;i++) q[i]=qq[i]/100.0; 50 for(int i=1;i<=n;i++) f[i]=1.0-q[i]; 51 dfs1(1,0);dfs2(1,0); 52 double ans=0.0; 53 for(int i=1;i<=n;i++) ans+=(1.0-f[i]); 54 printf("%.6lf",ans); 55 56 //3 57 //2 1 50 58 //2 3 50 59 //0 50 0
以上是关于概率充电器的主要内容,如果未能解决你的问题,请参考以下文章