【BZOJ 3566】 [SHOI2014]概率充电器 树上概率dp

    xiaoxiao2021-03-26  22

    首先明确,这里每一个节点的权值都是1,所以求期望就是求概率,答案=每一个节点通电的概率和,但是直接求通电的概率很不好求所以转化一下,求不通电的概率,然后1去就好了。

    又由于是一棵树所以很不好处理,对于一个节点来说有三种可能通电:

    1.自己通电

    2.由儿子导过来

    4.父亲导过来

    f[i]表示由下而上不能充电的概率 g[i]表示由上而下不能充电的概率最后答案就是:

    ∑1-f[i]*g[i]*(1-q[i])

    方程:

    f的很好求:f[u]*=(1-e[i].w)+e[i].w*(1-q[v])*f[v];//e[i].w是导线导电的概率,初始值为1

    但是

    g一开始我还因为这里wa了2发,就是它的父亲节点通电除了自己通电或则父亲的父亲导过来,还可以是父亲的其他儿子导过来所以:

    p[v]=(1-e[i].w)+e[i].w*(1-q[v])*f[v];

    g[v]=1-e[i].w+e[i].w*(1-q[u])*g[u]*f[u]/p[v];

    g[1]=1

    #include<cstdio> #include<cstring> #include<iostream> #define maxn 500021 using namespace std; double f[maxn],g[maxn],q[maxn],p[maxn]; //f[i]表示由下而上不能充电的概率 g[i]表示由上而下不能充电的概率 int n,head[maxn],tot=1; struct edge{int v,next;double w;}e[maxn*2]; void adde(int a,int b,double c){e[tot].v=b,e[tot].w=c,e[tot].next=head[a];head[a]=tot++;} void dfs(int u,int fa){ f[u]=1.0; for(int v,i=head[u];i;i=e[i].next){ if((v=e[i].v)==fa)continue; dfs(v,u); p[v]=(1-e[i].w)+e[i].w*(1-q[v])*f[v]; f[u]*=p[v]; } } void dfs2(int u,int fa){ for(int v,i=head[u];i;i=e[i].next){ if((v=e[i].v)==fa)continue; g[v]=1-e[i].w+e[i].w*(1-q[u])*g[u]*f[u]/p[v]; dfs2(v,u); } } int main(){ scanf("%d",&n); int a,b;double c; for(int i=1;i<n;i++){ scanf("%d%d%lf",&a,&b,&c);c/=100.0; adde(a,b,c),adde(b,a,c); } for(int i=1;i<=n;i++)scanf("%lf",q+i),q[i]/=100.0; g[1]=1.0; dfs(1,0);dfs2(1,0); double ans=0.0; for(int i=1;i<=n;i++) ans+=1-g[i]*f[i]*(1-q[i]); printf("%.6lf",ans); return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-664100.html

    最新回复(0)