【概率充电器】题解

真的是一道很有意思的题目

实际上,这道题与换根没啥关系,主要是与二次扫描有点关系

1. 前置知识简单讲解

1.1. 关于问题本身

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

什么是期望?(以下只是这个蒟蒻自学后所总结的,显然不会很严谨)

现在有 n n n 个事件,每个事件发生的概率为 p p p,期望值为 s s s,那么最终的期望值为:

∑ i = 1 n p i s i \sum\limits_{i=1}^np_is_i i=1npisi

看不懂?举个例子:

你要投一个骰子,求:的所得到的点数的期望

显然,有 6 6 6 个事件,它们发生的概率都是 1 6 \dfrac{1}{6} 61,而每一个事件的期望值分别为 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6(骰子的 6 6 6 个点数),则最终的期望为 1 6 × ( 1 + 2 + 3 + 4 + 5 + 6 ) = 3 \dfrac{1}{6}\times(1+2+3+4+5+6)=3 61×(1+2+3+4+5+6)=3

而对于本问题,事件就是元件是否进入充电状态,期望值为 1 1 1(充起了就会使充起的数量 + 1 +1 +1),那么,我们只需要将所有元件进入充电状态的可能性相加即可。

1.2. 有关概率

先掏出结论:

对于两个相互独立的事件 A , B A,B A,B,它们的概率分别为 a , b a,b a,b,则:事件 A , B A,B A,B 至少发生一个的概率为 a + b − a b a+b-ab a+bab

证明显然:

  1. A A A 发生, B B B 不发生的概率: a ( 1 − b ) a(1-b) a(1b)
  2. B B B 发生, A A A 不发生的概率: b ( 1 − a ) b(1-a) b(1a)
  3. A , B A,B A,B 都发生: a b ab ab

把它们加起来: a ( 1 − b ) + b ( 1 − a ) + a b = a + b − a b a(1-b)+b(1-a)+ab=a+b-ab a(1b)+b(1a)+ab=a+bab

这是一个极为重要的结论,后面会多次使用

2. 题解时间

对于一个元件 i i i,想要使它充上电,无非三种情况

  1. 自己给自己来电(劲啊
  2. 儿子给自己来电(How 孝顺 the son is!
  3. 祖先或祖先的其它儿子来电

考虑到祖先,自己,儿子之间会互相影响,有点麻烦,所以,我们首先只考虑情况 1 1 1 和情况 2 2 2

我们设dp[x]用来表示第 x x x 个元件充上电的概率,显然,情况 1 1 1 的概率为 a[x]/100,情况 2 2 2 的概率为 dp[y]*zy代表x的一个儿子,z表示连接这两个元件的导线的充电概率)

也很显然,要么只有情况 1 1 1 影响 dp[x],要么只有情况 2 2 2 影响 dp[x],要么情况 1 1 1 和情况 2 2 2 都影响 dp[x],两个事件至少发生一个,按照上面的公式,我们可以得到在只考虑情况 1 1 1 和情况 2 2 2 的情况下的dp[i]

代码:

void dfs(int x,int fa){
	for(int i=head[x];i;i=Next[i]){
		int y=ver[i];
		double z=edge[i];
		if(y^fa){
			dfs(y,x);
			dp[x]=dp[x]+dp[y]*z-dp[x]*dp[y]*z;//套公式
			//这里,我将 a[x] 的值直接输入到 dp[x] 里面去了
		}
	}
}

接下来,考虑加入情况 3 3 3

我们只考虑父亲转移儿子

对于 x x x 元件的父亲 f f f,它的转移情况有两种

A. 不是由 x x x 元件转移而来(设其概率为 a a a
B. 是由 x x x 元件转移而来(设其概率为 b b b

(这里为了区分前面的 1 , 2 , 3 1,2,3 1,2,3,使用了 A,B

显然,如果要让 f f f 来影响 x x x,那么, x x x 就不能影响 f f f你丫的搁这儿搁这儿呢

若连接 f , x f,x f,x 元件的导线的充电概率为 z z z,那么,情况 3 3 3 的概率实际上应为 a*z

思考: a a a 的求法

首先,不难看出,b应该等于dp[x]*z,那么,求a就不难了

由于,要么只有情况A影响dp[f],要么只有情况B影响dp[f],要么情况A和情况B都影响了dp[f],所以,套公式:a+dp[x]*z-a*dp[x]*z=dp[f]

a求出来之后,就可以将情况 3 3 3 代入了

但是注意,最终求出来的a是一个分数的形式,而分母是有可能为 0 0 0 ,注意特判

代码:

void DP(int x,int fa){
	for(int i=head[x];i;i=Next[i]){
		int y=ver[i];
		double z=edge[i];
		if(y^fa){
			if(dp[y]*z<=1+0.00000001&&dp[y]*z>=1-0.00000001){//判0,注意精度
				DP(y,x);		
				continue;
			}
			double tot=(dp[x]-dp[y]*z)/(1-dp[y]*z);//套公式
			dp[y]=dp[y]+tot*z-dp[y]*tot*z;
			DP(y,x);
		}
	}
}

3. 代码时间

404 Not Found

实际上,我甚至连两个关键函数都给你了,还有什么必要看完整代码吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值