zoukankan      html  css  js  c++  java
  • BZOJ3566 概率充电器 概率dp

    哼我就要正着推

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3566

    题意:节点有没有电看脸,线好不好看脸,问一个正常的亚洲人会给几个东西充上电。

    我就正着推了怎么地首先,我们定义一下数组含义,$f[x]$表示这个点有电的概率,$g[x]$表示这个点被自己和儿子充上电的概率。

    【普及选修2-3知识】

    概率的可加性:$P(X∨Y)=P(X)+P(Y)-P(X∧Y)$。

    那么这样$g[x]$就很好推了:$g[x]=g[没有v的x概率]+g[v]*l-g[没有v的x概率]*g[v]*l$,其中,$l$表示两点间连线带电概率。这个一遍从下到上搞上去就好了。

    问题在于这个$f[x]$上。首先$f[x]$一定包括$g[x]$,另外还有一部分是他的爸爸给他充上了电的概率,这就是我们接下来需要求的。

    首先我们可以肯定根节点$f[root]=g[root]$。

    接下来,我们再次考虑$f[x]$的求法:$f[x]=f[没有v的x]+g[v]*l-f[没有v的x]*g[v]*l$,然后我们使用高深的数学知识移项得到$f[x]-g[v]*l=f[没有v的x]*(1-g[v]*l)$,就可以得到爸爸没有这个儿子有电的概率,然后儿子的$f[v]$就是:$f[v]=g[v]+((f[x]-g[v]*l)/(1-g[v]*l))*l-g[v]*((f[x]-g[v]*l)/(1-g[v]*l))*l$

    啊好麻烦我后悔了(躺倒在沙滩上的一条咸鱼)(大概这就是做这道题每个正着推的人的心路历程)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 const int maxn=500005;
     8 const double eps=1e-8;
     9 struct node
    10 {
    11     int from,to,next;long double dis;
    12     node(){;}
    13     node(int u,int v,long double w,int x):from(u),to(v),dis(w),next(x){;}
    14 }edge[maxn<<1];
    15 int head[maxn],tot;
    16 void addedge(int u,int v,long double w)
    17 {
    18     edge[++tot]=node(u,v,w,head[u]);head[u]=tot;
    19 }
    20 int n,pa[maxn];
    21 long double f[maxn],g[maxn],p[maxn];
    22 void dfs1(int root,int fa)
    23 {
    24     pa[root]=fa;g[root]=p[root];
    25     for(int i=head[root];i;i=edge[i].next)
    26     {
    27         int v=edge[i].to;
    28         if(v!=fa)
    29         {
    30             dfs1(v,root);
    31             long double tmp=g[v]*edge[i].dis;
    32             g[root]=g[root]+tmp-g[root]*tmp;
    33         }
    34     }
    35 }
    36 long double ans;
    37 void dfs2(int root)
    38 {
    39     ans+=f[root];
    40     for(int i=head[root];i;i=edge[i].next)
    41     {
    42         int v=edge[i].to;
    43         if(v!=pa[root])
    44         {
    45             long double tmp=g[v]*edge[i].dis,temp=fabs(1-tmp)<=eps?1:(f[root]-tmp)/(1-tmp),tmp2=temp*edge[i].dis;
    46             f[v]=g[v]+tmp2-g[v]*tmp2;
    47             dfs2(v);
    48         }
    49     }
    50 }
    51 int haha()
    52 {
    53     scanf("%d",&n);
    54     for(int i=1;i<n;i++)
    55     {
    56         int x,y;double z;scanf("%d%d%lf",&x,&y,&z);long double dis=z/100.0;
    57         addedge(x,y,dis);addedge(y,x,dis);
    58     }
    59     for(int i=1;i<=n;i++){double x;scanf("%lf",&x);p[i]=x/100.0;}
    60     dfs1(1,0);f[1]=g[1];dfs2(1);
    61     printf("%0.6lf
    ",(double)ans);
    62 }
    63 int sb=haha();
    64 int main(){;}
    BZOJ3566
  • 相关阅读:
    Mutex 的正确打开方式
    常用 CMD 命令
    【LeetCode】在排序数组中查找元素的第一个和最后一个位置【三次二分】
    【LeetCode】搜索旋转排序数组【两次二分】
    【手写代码】计算1-n中总共有多少二进制1
    【手写代码】快速计算数字x有多少个二进制1
    【手写代码】建立二叉搜索树
    【LeetCode】下一个排列【找规律】
    【LeetCode】删除排序数组中的重复项&&移除特定元素【双指针,原地算法】
    【LeetCode】删除链表的倒数第N个节点【双指针法】
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7517786.html
Copyright © 2011-2022 走看看