【Luogu】P4284概率充电器(概率树形DP)
这题好神啊……
设f[i]为i没电的概率,初始化$f[i]=1-q[i]$
之后x的电有三个来源:
1.x自己有电
2.x的儿子给它传来了电
3.x的父亲给它传来了电
对于2和3操作分别做一次树形DP,第一次是用儿子推出父亲,第二次是用父亲推出儿子。
#include<cstdio> #include<algorithm> #include<cstring> #include<cctype> #include<cstdlib> #define maxn 500050 #define eps 1e-9 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } struct Edge{ int next,to;double val; }edge[maxn*2]; int head[maxn],num; inline void add(int from,int to,double val){ edge[++num]=(Edge){head[from],to,val}; head[from]=num; } double f[maxn]; double q[maxn]; void dfs(int x,int fa){ f[x]=1-q[x]; for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==fa) continue; dfs(to,x); f[x]*=1-(1-f[to])*edge[i].val; } return; } void dgs(int x,int fa){ for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==fa) continue; double ret=1-f[x]/(1-(1-f[to])*edge[i].val); if(ret>eps&&f[to]>eps) f[to]*=1-ret*edge[i].val; dgs(to,x); } return; } int main(){ int n=read(); for(int i=1;i<n;++i){ int from=read(),to=read(),p=read(); add(from,to,p*1.0/100); add(to,from,p*1.0/100); } for(int i=1;i<=n;++i) q[i]=read()*1.0/100; dfs(1,1); dgs(1,1); double ans=0; for(int i=1;i<=n;++i) ans+=1-f[i]; ans+=eps; printf("%.6lf",ans); return 0; }