【概率充电器】题解

文章详细解释了一道与二次扫描相关的数学问题,涉及元件进入充电状态的期望计算。通过介绍期望值的概念,用概率论中的独立事件概率和动态规划方法(DFS和DP)解决元件充电状态的问题。文章提供了关键的数学公式和代码片段,帮助理解解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

1. 前置知识简单讲解

1.1. 关于问题本身

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

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

现在有 nnn 个事件,每个事件发生的概率为 ppp,期望值为 sss,那么最终的期望值为:

∑i=1npisi\sum\limits_{i=1}^np_is_ii=1npisi

看不懂?举个例子:

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

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

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

1.2. 有关概率

先掏出结论:

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

证明显然:

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

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

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

2. 题解时间

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

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

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

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

也很显然,要么只有情况 111 影响 dp[x],要么只有情况 222 影响 dp[x],要么情况 111 和情况 222 都影响 dp[x],两个事件至少发生一个,按照上面的公式,我们可以得到在只考虑情况 111 和情况 222 的情况下的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] 里面去了
		}
	}
}

接下来,考虑加入情况 333

我们只考虑父亲转移儿子

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

A. 不是由 xxx 元件转移而来(设其概率为 aaa
B. 是由 xxx 元件转移而来(设其概率为 bbb

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

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

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

思考:aaa 的求法

首先,不难看出,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求出来之后,就可以将情况 333 代入了

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

代码:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值