BZOJ 3566 [SHOI2014]概率充电器 ——期望DP

期望DP。

补集转化,考虑不能被点亮的情况,

然后就是三种情况,自己不能亮,父亲不能点亮它,儿子不能点亮它。

第一次计算比较容易,第二次计算的时候需要出去第一次的影响,因为一条线只能传导一次

#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define maxn 1000005
 
int n;
int h[maxn],to[maxn],ne[maxn],en=0;
double w[maxn],f[maxn],g[maxn],tmp[maxn];
 
void add(int a,int b,double p)
{to[en]=b;ne[en]=h[a];w[en]=p;h[a]=en++;}
 
void dfs1(int o,int fa)
{
    for (int i=h[o];i>=0;i=ne[i])
    if (to[i]!=fa){
        dfs1(to[i],o);
        tmp[to[i]]=f[to[i]]+(1-f[to[i]])*(1-w[i]);
        f[o]*=tmp[to[i]];
    }
}
 
void dfs2(int o,int fa)
{
    double t;
    for (int i=h[o];i>=0;i=ne[i])
    if (to[i]!=fa)
    {
        t=tmp[to[i]]<1e-6?0:g[o]*f[o]/tmp[to[i]];
        g[to[i]]=t+(1-t)*(1-w[i]);
        dfs2(to[i],o);
    }
}
 
int main()
{
    memset(h,-1,sizeof h);
    scanf("%d",&n);
    for (int i=1;i<n;++i)
    {
        int a,b,p;
        scanf("%d%d%d",&a,&b,&p);
        add(a,b,p/100.0);add(b,a,p/100.0);
    }
    int c;
    F(i,1,n) scanf("%d",&c),f[i]=1-c/100.0;
    dfs1(1,0); g[1]=1.0; dfs2(1,-1);
    double ans=0.0;
    F(i,1,n) ans+=1-f[i]*g[i];
    printf("%.6lf\n",ans);
}

  

posted @ 2017-04-05 17:47  SfailSth  阅读(195)  评论(0编辑  收藏  举报