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); }