[SHOI2014]概率充电器 (树形DP)

105 篇文章 0 订阅
86 篇文章 0 订阅

题目
这个题。。。
如果我们只考虑从儿子到父亲的传输电,之后可以再用一个dfs从上至下更新父亲对儿子的贡献。
但是这个题需要求的是概率而非期望(直接算期望不好求),就没有那些什么线性性:
P ( A ∣ B ) = P ( A ) + P ( B ) − P ( A ) ∗ P ( B ) P(A|B) = P(A) + P(B) - P(A) * P(B) P(AB)=P(A)+P(B)P(A)P(B)
P ( A ) = P ( A ∣ B ) − P ( B ) 1 − P ( B ) P(A)=\frac {P(A|B)-P(B)}{1-P(B)} P(A)=1P(B)P(AB)P(B)
注意对于第二个式子,Claris大佬认为会除0,于是还存了当前的概率上有几个0,但其实是不需要的,如果 P ( B ) = 1 P(B)=1 P(B)=1,那么。。。下面是一定会通电的,直接赋值 d p = 1 dp=1 dp=1就行
A C   C o d e : {\rm AC \ Code:} AC Code:

#include<bits/stdc++.h>
#define maxn 500005
#define double long double
using namespace std;

int n;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
double cst[maxn<<1];
inline void Node(int u,int v,double ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=ct; }

double zc[maxn];

double dp[maxn];

void dfs(int now,int ff)
{
	dp[now] = zc[now];
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff)
		{
			dfs(to[i],now);
			double tmp = dp[to[i]] * cst[i];
			dp[now] = dp[now] + tmp - dp[now] * tmp;
		}
}

double dp2[maxn],ans;
void ser(int now,int ff)
{
	ans +=dp2[now];
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff)
		{
			double tmp = dp[to[i]] * cst[i];
			if(fabs(tmp - 1)<1e-8) dp2[to[i]] = 1;
			else
			{
				double pfa = (dp2[now]-tmp)/(1-tmp)*cst[i];
				dp2[to[i]] = dp[to[i]] + pfa - pfa * dp[to[i]];
			}
			ser(to[i],now);
		}
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v,p;
		scanf("%d%d%d",&u,&v,&p);
		
		Node(u,v,p/100.0),Node(v,u,p/100.0);
	}
	for(int i=1;i<=n;i++) scanf("%Lf",&zc[i]),zc[i]/=100;
	
	dfs(1,0);
	dp2[1] = dp[1];
	ser(1,0);
	
	printf("%.6Lf",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值