正题
题目链接:https://www.luogu.com.cn/problem/P4284
题目大意
nnn个点的一棵树,每个点有pip_ipi概率通电,每个边有一定概率可以导电。求期望有电的节点个数。
解题思路
发现考虑通电概率很难,所以我们可以考虑不通电的概率。
如果只是计算一个点的话很方便,我们统计一下以一个点为根时候每个点的通电概率fif_ifi即可。
有转移方程fx=(1−px)∗∏(fy+(1−fy)∗(1−w))f_x=(1-p_x)*\prod (\ f_y+(1-f_y)*(1-w)\ )fx=(1−px)∗∏( fy+(1−fy)∗(1−w) )
然后换根计算即可。
时间复杂度O(n)O(n)O(n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e5+10;
struct node{int to,next;double w;
}a[N*2];
int n,tot,ls[N];
double f[N],g[N],p[N],ans;
void addl(int x,int y,double w){a[++tot].to=y;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot;return;
}
void dfs(int x,int fa){f[x]=1.0-p[x]; for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;dfs(y,x);f[x]*=f[y]+(1.0-f[y])*(1.0-a[i].w);}return;
}
void dp(int x,int fa){for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;double k=g[x]/(f[y]+(1.0-f[y])*(1-a[i].w));g[y]=f[y]*(k+(1.0-k)*(1.0-a[i].w));dp(y,x);}ans+=g[x];return;
}
int main()
{scanf("%d",&n);for(int i=1;i<n;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);addl(x,y,(1.0*w)/100.0);addl(y,x,(1.0*w)/100.0);}for(int i=1;i<=n;i++)scanf("%lf",&p[i]),p[i]/=100;dfs(1,1);g[1]=f[1];dp(1,1);printf("%lf",n-ans); return 0;}