概率充电器

概率充电器

内存限制:256 MiB 时间限制:2000 ms 标准输入输出
 
 
题目描述

著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!”
SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?

输入格式

第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的充电元件,通电概率为 p。
第 n+2 行 n 个整数:qiq_iqi​​。表示 i 号元件直接充电的概率为 qi。

输出格式

输出一行一个实数,为进入充电状态的元件个数的期望,四舍五入到六位小数

样例
样例输入
3 
1 2 50 
1 3 50 
50 0 0
样例输出
1.000000
数据范围与提示

对于 100%的数据,n500000,0p,qi100。

 

 
   见到期望首先想dp。 
  
直接想联通的概率比较难码,故思考f表示不联通的概率,最终用1-f就表示联通的概率。
f[x]=不连通的概率,p[x]表示这个点直接联通概。
我们为了避免后效性高斯消元(高斯消元消不起)必须选择其他方法。
思考:我们先求出来父亲对儿子贡献,再求出儿子对父亲贡献就好了(其实就是常规树形dp)。
我们先考虑儿子对父亲的贡献。
父亲可以由每一个儿子转移过来,
父亲不连通的概率等于自己本身不连的概率乘以所有自己儿子不相连的概率
首先儿子需要联通才可以由儿子联通转移过来,用1-f[x]表示自己儿子联通的概率
(1-f)*w表示当儿子联通的时候由儿子转移过来的概率
1-...等于不连通的概率
再让他们都相乘
于是得到

$f[x]=(1-p[x])*Π1-(1-f[son])*联通概率$
然后计算儿子的概率由父亲贡献
考虑f[v]表示除了v以外贡献
首先f[v]=1-当所有父亲被联通概率-其联通时的概率*这个边联通的概率
得到
$f[v]=(1-\frac{1-f[x]}{1-(1-f[son])}*联通概率)*联通概率$
思考
父亲被别的点转移过来的概率(除去v点)
$1-{\frac{f[x]}{1-(1-f[v]*w)}}$
1-f 表示自己儿子被转移过来的概率 (1-f)*w表示父亲与这个点相连的概率
1-..表示包含v在内的不相连的概率
再用 f[x]/...不连通的概率
至于为什么除呢 ?
例如得不病 1/5 ,不得乙病3/5 ,不甲病1/3。那么1/5*5/3=1/3=不甲病 ,1-表示联通的概率
以下依然是本人丑陋代码

 1 #include<bits/stdc++.h>
 2 #define ll int
 3 #define db double
 4 #define e 1e-9
 5 #define inf 0x7fffffff
 6 #define A 1000100
 7 using namespace std;
 8 ll n,m,head[A],ver[A],next[A],tot=0,xx,yy;
 9 db gai[A],zz,gl[A],f[A];
10 bool flag[A];
11 void add(ll x,ll y,db gailv)
12 {
13     next[++tot]=head[x];
14     head[x]=tot;
15     ver[tot]=y;
16     gai[tot]=gailv*0.01;
17 }
18 inline ll R()
19 {
20     ll X=0,F=1;char c=getchar();
21     while(!isdigit(c)) c=='-'?F=-1:F=F,c=getchar();
22     while(isdigit(c)) X=(X<<1)+(X<<3)+(c-'0'),c=getchar();
23     return F*X;
24 }
25 db dfs1(ll x,ll fa)
26 {
27     for(ll i=head[x];i;i=next[i])
28     {
29         ll y=ver[i];db g=gai[i];
30         if(y==fa) continue;    
31         
32 //        printf("x=%d y=%d fx=%lf fy=%lf %lf=(1-f[y])*g\n",x,y,f[x],f[y],(1-f[y])*g);
33         dfs1(y,x);f[x]*=(1-(1-f[y])*g);
34     }
35 }
36 void dfs2(ll x,ll fa)
37 {
38     db r;
39     for(ll i=head[x];i;i=next[i])
40     {
41         ll y=ver[i];db g=gai[i];
42         if(y==fa) continue;
43         r=1.0-(f[x])/(1-(1-f[y])*g);
44         if(fabs(r)>e&&fabs(f[y])>e)
45         f[y]*=1-r*g;
46         dfs2(y,x);
47     }
48 }
49 int main()
50 {
51     n=R();
52     for(ll i=1;i<n;i++)
53     {
54         xx=R(),yy=R();scanf("%lf",&zz);
55         add(xx,yy,zz);
56         add(yy,xx,zz);
57     }
58     for(ll i=1;i<=n;i++)
59     {
60         scanf("%lf",&gl[i]);
61         gl[i]*=0.01;
62         f[i]=1-gl[i];
63     }
64     memset(flag,0,sizeof(flag));dfs1(1,inf);
65     memset(flag,0,sizeof(flag));dfs2(1,inf);
66     db ans=0;
67     for(ll i=1;i<=n;i++)
68         ans+=1-f[i];
69     printf("%.6lf\n",ans);
70 }

View Code

 通过写这个题解,我深查自己语言表达能力欠缺。

 

转载于:https://www.cnblogs.com/znsbc-13/p/11136912.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值