题目大意:给定一棵树,每个点初始有一个概率为1,为1的节点会沿着边以边权上的概率向四周扩散,求最终期望有多少个点是1
OTZ 不想写题解了贴个代码吧= =
如果有不明白做法的直接问我就好了= =
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 500500 #define EPS 1e-7 using namespace std; struct abcd{ int to,next; long double f; }table[M<<1]; int head[M],tot; int n,fa[M]; long double a[M],f[M],g[M],ans; //f[i]表示子树中节点(不包括自身)对i节点的影响 //g[i]表示子树以外节点以及自身对i节点的影响 void Add(int x,int y,long double z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } long double Combination(long double x,long double y) { return x+y-x*y; } void Tree_DP1(int x) { int i; for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) { fa[table[i].to]=x; Tree_DP1(table[i].to); f[x]=Combination(f[x],Combination(f[table[i].to],a[table[i].to])*table[i].f); } } void Tree_DP2(int x) { static int stack[M]; static long double from[M],pref[M],suff[M]; int i,top=0; g[x]=Combination(g[x],a[x]); for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) { stack[++top]=table[i].to; from[top]=table[i].f; } pref[0]=suff[top+1]=0; for(i=1;i<=top;i++) pref[i]=Combination(pref[i-1],Combination(f[stack[i]],a[stack[i]])*from[i]); for(i=top;i;i--) suff[i]=Combination(suff[i+1],Combination(f[stack[i]],a[stack[i]])*from[i]); for(i=1;i<=top;i++) g[stack[i]]=from[i]*Combination(g[x],Combination(pref[i-1],suff[i+1])); for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) Tree_DP2(table[i].to); } int main() { int i,x,y,z; cin>>n; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); Add(x,y,z/100.0); Add(y,x,z/100.0); } for(i=1;i<=n;i++) { scanf("%d",&x); a[i]=x/100.0; } Tree_DP1(1); Tree_DP2(1); for(i=1;i<=n;i++) ans+=Combination(f[i],g[i]); printf("%.6lf\n",(double)ans); return 0; }
BZOJ 3566 SHOI2014 概率充电器 树形期望DP
原文地址:http://blog.csdn.net/popoqqq/article/details/43406517