【BZOJ3566】概率充电器(动态规划)
题面
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
Sample Output
1.000000
HINT
对于 100%的数据,n≤500000,0≤p,qi≤100。
题解
很明显要求出所有点的通电的概率,直接相加即可
但是这个概率不好算,我们反过来,求每个点不通电的概率。
设(f[i])表示(i)不通电的概率
(f[u]=(1-q[u])*prod_v(f[v]+(1-f[v])*(1-p[u,v])))
但是这样子少考虑了父亲的影响
于是再做一遍(dp),考虑父亲节点的影响就行了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 555555
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Line{int v,next;double w;}e[MAX<<1];
int h[MAX],cnt=1,n;
inline void Add(int u,int v,double w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
double f[MAX],g[MAX],q[MAX],pf[MAX];
void dfs(int u,int ff)
{
f[u]=1.0-q[u];int tt=0;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==ff)continue;
pf[v]=e[i].w;dfs(v,u);
double P=f[v]+(1-f[v])*(1-e[i].w);
if(P>0)f[u]=f[u]*P;
else ++tt;
}
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==ff)continue;
double P=f[v]+(1-f[v])*(1-e[i].w);
if(P>0){if(!tt)g[v]=f[u]/P;}
else if(tt==1)g[v]=f[u];
}
if(tt)f[u]=0;
}
void DFS(int u,int ff)
{
if(ff)
g[u]=g[u]*(g[ff]+(1-g[ff])*(1-pf[ff]));
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)DFS(e[i].v,u);
}
int main()
{
n=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),p=read();
Add(u,v,0.01*p);Add(v,u,0.01*p);
}
for(int i=1;i<=n;++i)q[i]=0.01*read();
dfs(1,0);DFS(1,0);
for(int i=1;i<=n;++i)f[i]=f[i]*(g[i]+(1-g[i])*(1-pf[i]));
double ans=0;
for(int i=1;i<=n;++i)ans+=1.0-f[i];
printf("%.6lf
",ans);
return 0;
}