• 火山喷发 计蒜客16862 NOIP模拟赛 概率DP


    题目描述

    输入格式

    输出格式

    数据范围与约定

    对于 10% 的数据 N=1

    对于 30% 的数据 N=2。

    对于全部数据 N4,M≤120 , A_i≤50。

    样例输入1

    1 2
    1

    样例输出1

    0.000000

    样例输入2

    3 15
    2 12 2

    样例输出2

    0.001684
    0.996632
    0.001684

    题目来源

    2017 NOIP 提高组模拟赛(三)Day1

    什么?你想用DFS?复杂度可能是O(4*120!),也就大概是的复杂度。

    所以,这道题很明显就是一道概率DP的题~

    DP数组表示?

    对于本题,不妨 f[i][j][k][v] 表示1、2、3、4种生物的生命值为i、j、k、v的概率

    初始值?

    很显然,对于读入的 a[1...n],可以有 f[a[1]][a[2]][a[3]][a[4]]=1 (没有读入的生命值为0)

    怎么转移?

    对于a[1]+a[2]+a[3]+a[4]<=m的情况,直接输出n个0.000000即可。(难道这还用问为什么?

    若a[1]+a[2]+a[3]+a[4]>m,开始dp。

     1 dp[a[1]][a[2]][a[3]][a[4]]=1;
     2     for (register int i=a[1];i>=0;--i)
     3         for (register int v=a[2];v>=0;--v)
     4             for (register int k=a[3];k>=0;--k)
     5                 for (register int j=a[4];j>=0;--j)
     6                 {
     7                     if(a[1]-i+a[2]-v+a[3]-k+a[4]-j>m) continue;
     8                     register int cnt=0;
     9                     if(i)++cnt; if(v)++cnt; if(k)++cnt; if(j)++cnt;
    10                     if(!cnt) continue;
    11                     double gl=1.000000/(double)cnt;
    12                     if(i) dp[i-1][v][k][j]+=gl*dp[i][v][k][j];
    13                     if(v) dp[i][v-1][k][j]+=gl*dp[i][v][k][j];
    14                     if(k) dp[i][v][k-1][j]+=gl*dp[i][v][k][j];
    15                     if(j) dp[i][v][k][j-1]+=gl*dp[i][v][k][j];
    16                 }

    方程的含义是显而易见的。由当前状态推向下一状态,并乘以对应的概率。

    如何求得答案?

    举个栗子,对于一个对第一个生物生存的概率询问,我们遍历求和,sum=Σf[0][j][k][v],其中j<=a[2],k<=a[3],v<=a[4],且 a[1]+a[2]-j+a[3]-k+a[4]-v==m

    这样,我们求到的sum是第一个生物死亡的概率,我们回答 1.0-sum 即可

    附上AC代码

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 template<class _T>inline void read(_T &_a)
     5 {
     6     char _ch=getchar();_a=0;
     7     while(_ch<'0'||_ch>'9')_ch=getchar();
     8     while(_ch>='0'&&_ch<='9'){_a=(_a<<3)+(_a<<1)+_ch-'0';_ch=getchar();}
     9 }
    10 
    11 const int maxn=5;
    12 int n,m,a[maxn];
    13 double dp[51][51][51][51];
    14 
    15 int main()
    16 {
    17     freopen("volcano.in","r",stdin);
    18     freopen("volcano.out","w",stdout);
    19     read(n); read(m);
    20     for (register int i=1;i<=n;++i) read(a[i]);
    21     if(m>=a[1]+a[2]+a[3]+a[4])
    22     {
    23         for (register int i=1;i<=n;++i) printf("0.000000
    ");
    24         return 0;
    25     }
    26     dp[a[1]][a[2]][a[3]][a[4]]=1;
    27     for (register int i=a[1];i>=0;--i)
    28         for (register int v=a[2];v>=0;--v)
    29             for (register int k=a[3];k>=0;--k)
    30                 for (register int j=a[4];j>=0;--j)
    31                 {
    32                     if(a[1]-i+a[2]-v+a[3]-k+a[4]-j>m) continue;
    33                     register int cnt=0;
    34                     if(i)++cnt; if(v)++cnt; if(k)++cnt; if(j)++cnt;
    35                     if(!cnt) continue;
    36                     double gl=1.000000/(double)cnt;
    37                     if(i) dp[i-1][v][k][j]+=gl*dp[i][v][k][j];
    38                     if(v) dp[i][v-1][k][j]+=gl*dp[i][v][k][j];
    39                     if(k) dp[i][v][k-1][j]+=gl*dp[i][v][k][j];
    40                     if(j) dp[i][v][k][j-1]+=gl*dp[i][v][k][j];
    41                 }
    42     for (register int i=1;i<=n;i++)
    43     {
    44         register double ans=0;
    45           if (i==1)
    46               for (register int j=0;j<=a[2];++j)
    47                 for (register int k=0;k<=a[3];++k)
    48                     for (register int p=0;p<=a[4];++p)
    49                         if (a[1]+a[2]-j+a[3]-k+a[4]-p==m)
    50                             ans+=dp[0][j][k][p];
    51         if (i==2)
    52             for (register int j=0;j<=a[1];++j)
    53                 for (register int k=0;k<=a[3];++k)
    54                     for (register int p=0;p<=a[4];++p)
    55                         if (a[1]-j+a[2]+a[3]-k+a[4]-p==m)
    56                             ans+=dp[j][0][k][p];    
    57         if (i==3)
    58             for (register int j=0;j<=a[1];++j)
    59                 for (register int k=0;k<=a[2];++k)
    60                     for (register int p=0;p<=a[4];++p)
    61                         if (a[1]-j+a[2]-k+a[3]+a[4]-p==m)
    62                             ans+=dp[j][k][0][p];    
    63         if (i==4)
    64             for (register int j=0;j<=a[1];++j)
    65                 for (register int k=0;k<=a[2];++k)
    66                     for (register int p=0;p<=a[3];++p)
    67                         if (a[1]-j+a[2]-k+a[3]-p+a[4]==m)
    68                             ans+=dp[j][k][p][0];    
    69         printf("%lf
    ",1.000000-ans);
    70     }
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    idea中代码提交流程(git版)
    《如何做好软件设计》:设计原则
    用基础Array数组实现动态数组、链表、栈和队列
    使用Redis+SpringBoot实现定时任务测试
    分布式锁的三种实现方式
    RabbitMQ镜像队列集群搭建、与SpringBoot整合
    RabbitMQ简介、安装、基本特性API--Java测试
    分布式文件系统FastDFS简介、搭建、与SpringBoot整合实现图片上传
    Elasticsearch--Logstash定时同步MySQL数据到Elasticsearch
    Elasticsearch 分片集群原理、搭建、与SpringBoot整合
  • 原文地址:https://www.cnblogs.com/jaywang/p/7719699.html
Copyright © 2020-2023  润新知