SHOI 2014 概率充电器 题解

题目传送门

题目大意: 给出一棵树,第 i i i 个节点有 a i a_i ai 的概率有电,第 i i i 条边有 e i e_i ei 的概率导电,问期望有几个节点有电。

题解

很经典的 d p dp dp 套路,第一次 d p dp dp 求出 f [ i ] f[i] f[i],表示子树对 i i i 的贡献,也就是只看子树的情况下,自己有电的概率。然后第二次 d p dp dp 时带着祖先以及兄弟们的贡献跑即可。

代码如下:

#include <cstdio>
#define maxn 500010

int n;
double a[maxn];
struct edge{int y,next;double z;};
edge e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y,int z)
{
	e[++len]=(edge){y,first[x],z/100.0};
	first[x]=len;
}
double f[maxn];
void dfs1(int x,int fa)
{
	f[x]=1.0-a[x];//先记录没电的概率
	for(int i=first[x];i;i=e[i].next)
	if(e[i].y!=fa)dfs1(e[i].y,x),f[x]*=1.0-f[e[i].y]*e[i].z;
	//所有没电的概率乘起来,再用1减,就是有电的概率了
	f[x]=1.0-f[x];
}
double ans=0.0;
void dfs2(int x,int fa,double FA)
{
	ans+=1.0-(1.0-f[x])*(1.0-FA);
	for(int i=first[x];i;i=e[i].next)
	if(e[i].y!=fa)
	{
		if(e[i].z!=0.0&&f[e[i].y]!=1.0)//这两个是用来判掉除0的情况
		dfs2(e[i].y,x,(1.0-(1.0-f[x])/(1.0-f[e[i].y]*e[i].z)*(1.0-FA))*e[i].z);
		else dfs2(e[i].y,x,0.0);
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1,x,y,z;i<n;i++)
	scanf("%d %d %d",&x,&y,&z),
	buildroad(x,y,z),buildroad(y,x,z);
	for(int i=1;i<=n;i++)scanf("%lf",&a[i]),a[i]/=100.0;
	dfs1(1,0);dfs2(1,0,0.0);
	printf("%.6lf",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值