bzoj 3566 概率充电器 (树形DP+概率DP)
3566: [SHOI2014]概率充电器
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 327 Solved: 140
[Submit][Status][Discuss]
Description
著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!
”
SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?
Input
第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的
充电元件,通电概率为 p%。
第 n+2 行 n 个整数:qi。表示 i 号元件直接充电的概率为 qi%。
Output
输出一行一个实数,为能够覆盖所有用户的最小椭圆的半短轴长,四舍五入到三位小数。
Sample Input
3
1 2 50
1 3 50
50 0 0
样例二:
5
1 2 90
1 3 80
1 4 70
1 5 60
100 10 20 30 40
Sample Output
1.000000
样例二:
4.300000
题目连接:http://www.lydsy.com/JudgeOnline/problem.php?id=3566
转载自:http://blog.csdn.net/t1019256391/article/details/28887161
首先普及一个概率公式 P(A+B)=P(A)+P(B)-P(AB)
题意:一些充电元件和导线构成一棵树,充电元件是否能充电有2种情况,
1、它自己有qi%的概率充电
2、与它相邻的元件通过导线给它充电(导线有p%的概率导通)
求最终充了电的元件的期望
题解:首先可以将元件能否充电分成3种情况考虑,
1、它自己给自己充好了电
2、它的儿子方向给它传送了电
3、它的父亲方向给它传送了电。
对于1,题目已经给出可以直接赋值,
对于2,可以通过一次树的深度遍历求得。pson[now]=pson[now] + pson[to]*edge_p - pson[now]*pson[to]*edge_p
对于3,麻烦一点,因为2中我们已经求得当前点(now)的儿子们给当前点的贡献,现在要求当前点给它的某个儿子(to)的贡献,这里要计算的话,就必须要排除之前to->now的,(想想若2中计算了to->now的概率,现在又要计算now->to的概率,明显出现了循环)具体公式推导见代码

设y = now点除了从to点来的电 的充电概率,dp[i]表示i点的充电概率,pson[i]表示在i的子树中,i的充电概率
pson[to]*p + y - pson[to]*p*y=dp[now] 这是第二个式子推导过程
(1-pson[to]*p)*y=dp[now]-pson[to]*p
y=(dp[now]-pson[to]*p)/(1-pson[to]*p);
dp[to]=pson[to] + y*p - pson[to]*y*p;
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<iostream>
#include<cmath>
using namespace std;
#define eps 1e-6
struct edge
{
int to,next;
double p;
} e[2000000];
int head[500005],en;
double pson[500005];
double dp[500005];
double ans=0;
void add(int a,int b,double c)
{
e[en].to=b;
e[en].p=c;
e[en].next=head[a];
head[a]=en++;
}
void dfs(int now,int fa)
{
for(int i=head[now]; ~i; i=e[i].next)
{
int to=e[i].to;
double p=e[i].p;
if(to==fa) continue;
dfs(to,now);
pson[now]=pson[now]+pson[to]*p-pson[now]*pson[to]*p;
}
}
bool cmp(double a,double b)
{
return fabs(a-b)<eps;
}
void dfs2(int now,int fa)
{
ans+=dp[now];
for(int i=head[now]; ~i; i=e[i].next)
{
int to=e[i].to;
double p=e[i].p;
if(to==fa) continue;
double tmp=(1-pson[to]*p);
if(cmp(tmp,0)) dp[to]=1.0;
else
{
double y=(dp[now]-pson[to]*p)/(1.0-pson[to]*p);
dp[to]=pson[to] + y*p - pson[to]*y*p;
}
dfs2(to,now);
}
}
int main()
{
int n,a,b,c;
scanf("%d",&n);
memset(head,-1,sizeof(head));
en=0;
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c/100.0);
add(b,a,c/100.0);
}
for(int i=1; i<=n; i++)
{
scanf("%lf",&pson[i]);
pson[i]/=100.0;
}
dfs(1,-1);
dp[1]=pson[1];
dfs2(1,-1);
printf("%.6f\n",ans);
return 0;
}


浙公网安备 33010602011771号