P4284 [SHOI2014]概率充电器(概率期望,换根dp,条件概率)

题意:给出一颗n个点,n-1条边的树,每个结点都有其初始化的被点亮的概率,每条边也有其可以通电的概率,求能被点亮的灯的数量的期望。

分析与总结:通过这道树形dp,加深了对换根的理解,对于解决一些有依赖性关系的问题,我们可以考虑高斯消元/换根dp,主要套路为先一遍dfs求出每个结点只考虑子节点中贡献,那么作为根,它的答案就是和我们想求的一致的。然后考虑换根,建议画图理解,主要思想是将父节点中的贡献排除这个点的贡献(在这里是个条件概率公式),然后这个点依赖是它的子树和父节点连接的那一坨的贡献。
Latex太烦了。
贴个手写学习笔记
在这里插入图片描述

const int N = 5e5 + 5;
vector<pair<int, double> >G[N];
double q[N], f[N], g[N];
void dfs(int u, int fa)
{
	f[u] = (1 - q[u]);
	for (auto i : G[u])
	{
		if (i.first == fa)continue;
		dfs(i.first, u);
		f[u] *= (1 - i.second + i.second*f[i.first]);
	}
}
double another(int u, int fa, double w)
{
	return g[fa] / (1 - w + w * f[u]);
}
void dfs2(int u, int fa)
{
	if (u == 1)g[u] = f[u];
	for (auto i : G[u])
	{
		if (i.first == fa)continue;
		g[i.first] = f[i.first] * (1 - i.second + i.second*another(i.first, u, i.second));
		dfs2(i.first, u);
	}
}
int main()
{
#ifndef ONLINE_JUDGE 
	freopen("in.txt", "r", stdin);
#endif

	int n;cin >> n;
	f(i, 1, n - 1)
	{
		int a = in(), b = in(), p = in();
		double gp = 1.0*p / 100;
		G[a].emplace_back(pair<int, double>{b, gp});
		G[b].emplace_back(pair<int, double>{a, gp});
	}
	f(i, 1, n) {
		int p = in();
		q[i] = 1.0*p / 100;
	}
	dfs(1, -1);
	dfs2(1, -1);
	double res = 0.0;
	f(i, 1, n)res += 1 - g[i];
	printf("%.6lf\n", res);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值