【BZOJ3566】【SHOI2014】概率充电器(概率与期望DP)

在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
using namespace std;
const int N=500010;
inline int read(){
    int x=0,f=1;
	char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
int n,head[N],cnt=-1;
struct Edge{
    int to,nxt;double w;
}edge[N<<1];
void add_edge(int u,int v,double w){
    edge[++cnt]=(Edge){v,head[u],w};head[u]=cnt;
    edge[++cnt]=(Edge){u,head[v],w};head[v]=cnt;
}
double f1[N],f2[N],q[N];
//f1 其子树令其亮
//f2 整棵树令其亮 
void dfs1(int u,int f){
    f1[u]=q[u];
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].to;
		if(v==f) continue;
        dfs1(v,u);
        double tmp=edge[i].w*f1[v];
        f1[u]=(f1[u]+tmp-f1[u]*tmp);
        //P(A+B)=P(A)+P(B)-P(AB)
    }
}
void dfs2(int u,int f,double w){
    if(fabs(1.0-f1[u]*w)>=1e-6){
        double t1=(f2[f]-f1[u]*w)/(1.0-f1[u]*w);
        f2[u]=(f1[u]+t1*w-f1[u]*t1*w);
    }
    else f2[u]=f1[u];
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].to;
		if(v==f) continue;
        dfs2(v,u,edge[i].w);
    }
}
int main(){
    memset(head,-1,sizeof(head));
    n=read();
	int t1,t2,t3;
    for(int i=1;i<n;i++){
        t1=read();t2=read();t3=read();
        add_edge(t1,t2,(double)t3*0.01);
    }
    for(int i=1;i<=n;i++) 
		q[i]=(double)read()*0.01;
    dfs1(1,0);
	dfs2(1,0,0);
    double ans=0;
    for(int i=1;i<=n;i++) ans+=f2[i];
    printf("%.6lf\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Emma2oo6/article/details/99689132