zoukankan      html  css  js  c++  java
  • 概率dp入门

    /*poj 2096
    第一道概率dp看别人的思路,不过总算理解为什么求期望从后往前了
    地址:http://blog.csdn.net/morgan_xww/article/details/6774708
    */
    #include<stdio.h>
    #include<string.h>
    #define N  1100
    double dp[N][N];
    int main() {
        int n,s,i,j;
        while(scanf("%d%d",&n,&s)!=EOF) {
            memset(dp,0,sizeof(dp));
            for(i=n;i>=0;i--)
            for(j=s;j>=0;j--) {
                if(i==n&&j==s)continue;
                dp[i][j]=(n*s+dp[i+1][j]*(n-i)*j+dp[i][j+1]*i*(s-j)+dp[i+1][j+1]*(n-i)*(s-j))/(n*s-i*j);
            }
            printf("%.4f
    ",dp[0][0]);
        }
    return 0;}
    
    /*
    hdu  3853
    有一个坑,到达自身的概率为1的话,就不用加到上一个
    */
    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #define eps 1e-10
    #define N  1100
    struct node {
       double a,b,c;
    }ma[N][N];
    double dp[N][N];
    int main() {
           int n,m,i,j;
           while(scanf("%d%d",&n,&m)!=EOF) {
            for(i=0;i<n;i++)
            for(j=0;j<m;j++)
            scanf("%lf%lf%lf",&ma[i][j].a,&ma[i][j].b,&ma[i][j].c);
            memset(dp,0,sizeof(dp));
            for(i=n-1;i>=0;i--)
            for(j=m-1;j>=0;j--) {
                if(i==n-1&&j==m-1)continue;
                if(fabs(1-ma[i][j].a)<eps)continue;//对于不能到达的不用计算
                dp[i][j]=(dp[i+1][j]*ma[i][j].c+dp[i][j+1]*ma[i][j].b+2)/(1-ma[i][j].a);
            }
            printf("%.3f
    ",dp[0][0]);
           }
    return 0;}
    
    /*
    hdu  4405
    只需处理以下可以直接到达的关系就可以了
    */
    #include<stdio.h>
    #include<string.h>
    #include<map>
    using namespace std;
    #define N 110000
    double dp[N];
    int f[N];
    int main() {
          int n,m,i,a,b;
          double kk;
          while(scanf("%d%d",&n,&m),n||m) {
            memset(dp,0,sizeof(dp));
            memset(f,-1,sizeof(f));
            while(m--) {
              scanf("%d%d",&a,&b);
               f[a]=b;
            }
            for(i=n-1;i>=0;i--) {
                if(f[i]==-1)
                dp[i]=dp[i+1]/6+dp[i+2]/6+dp[i+3]/6+dp[i+4]/6+dp[i+5]/6+dp[i+6]/6+1.0;
                else
                    dp[i]=dp[f[i]];
            }
            printf("%.4f
    ",dp[0]);
          }
    return 0;}
    
    /*
    sgu495
    m个人是独立的
    n个礼物每一个都不被选中的概率是(n-1)/n;
    n个礼物都不被选中的期望为n*pow(d,m);
    */
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define N  1100
    int main() {
       int n,m;
       double d,sum;
       while(scanf("%d%d",&n,&m)!=EOF) {
         d=(double)(n-1)/n;
         sum=1.0*n-1.0*n*pow(d,m);
          printf("%.10f
    ",sum);
       }
    return 0;}
    
    /*
    sgu495
    第二种做法很好
    m个人是独立的
    从人考虑:
    每个人都有可能得到1个礼物,但是第i个人得到1个礼物的概率与第i-1个人得到礼物的概率有关
     如果第i-1个人的到礼物,那么第i个人得到1个礼物的概率为dp[i-1]*(dp[i-1]-1.0/n);
     如果第i-1个人没有得到,那么第i个人得到1个礼物的概率为dp[i-1]*(1-dp[i-1]);
    */
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define N  110000
    double   dp[N];
    int main() {
       int n,m,i;
       double d,sum;
       while(scanf("%d%d",&n,&m)!=EOF) {
            dp[1]=1.0;sum=0;
          for(i=2;i<=m;i++) {
          dp[i]=1*((1-dp[i-1])*dp[i-1])+1*(dp[i-1]*(dp[i-1]-1.0/n));
          sum+=dp[i];
          }
          printf("%.10f
    ",sum+1.0);
       }
    return 0;}
    
    /*
    cf 148D
    理解概率的从前到后处理很好!
    先确定边界,从边界出发进行dp
    题意:王妃和龙轮流从袋子里那老鼠,如果王妃先拿到白老鼠,如果龙先拿到白老鼠那么龙赢,那么王菲赢,如果两人都没有取到
    白老鼠那么龙赢.
    求概率从前往后,先处理边界,
    参考博客:http://www.cnblogs.com/kuangbin/archive/2012/10/04/2711184.html
    dp[i][j]代表剩余i只白鼠j只黒鼠时王妃赢的概率
    三种情况王妃赢
    1.王妃抓到一只白老鼠,王菲赢了i/(i+j);
    2.w王妃抓到一只黑老鼠,龙抓到一只黑老鼠,跑了一只黑老鼠,那么赢的概率需要用到dp[i][j-3];
    1.0*j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3];
    3.王菲抓到一只黑老鼠,龙抓到一只黑老鼠,跑了一只白老鼠,那么赢的概率需要用到dp[i-1][j-2]
    1.0*j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2]
    并且保证合法
    */
    #include<stdio.h>
    #include<string.h>
    #define N  1100
    double dp[N][N];
    int main() {
        int n,m,i,j;
        while(scanf("%d%d",&n,&m)!=EOF) {
                memset(dp,0,sizeof(dp));
            for(i=1;i<=n;i++)dp[i][0]=1;
            for(i=1;i<=m;i++)dp[0][i]=0;
            for(i=1;i<=n;i++)
            for(j=1;j<=m;j++) {
                dp[i][j]+=1.0*i/(i+j);
                 if(j>=2)
                    dp[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2];
                    if(j>=3)
                        dp[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3];
            }
            printf("%.10f
    ",dp[n][m]);
        }
    return 0;}
    
    /*
    题意:
    一只吸血鬼,有n条路给他走,每次他随机走一条路,
    每条路有个限制,如果当时这个吸血鬼的攻击力大于
    等于某个值,那么就会花费t天逃出去,否则,花费1天
    的时间,并且攻击力增加,问他逃出去的期望天数
    因为可能有许多种情况,并且可以重复出现,所以记忆化搜索
    比如在某些条件下f+a[1]+a[2]和f+a[2]+a[1],会重复出现所以记忆
    */
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define  N  21000//因为f和a[i]的值都是10000所以
    double  dp[N];
    int a[N];
    int n;
    double dfs(int f)
    {
        if(dp[f]>0)return dp[f];
        int i;
        for(i=1; i<=n; i++)
        {
            if(f>a[i])
            {
                double temp=(1.0+sqrt(5.0))/2*a[i]*a[i];
                int t=(int)temp;
                dp[f]+=1.0*t*1.0/n;
            }
            else
                dp[f]+=(1.0+dfs(f+a[i]))*1.0/n;//当前能够走出去的天数由f+a[i]后的期望天数+1乘于概率得到
        }
        return dp[f];
    }
    int main()
    {
        int m,i;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(i=1; i<=n; i++)
                scanf("%d",&a[i]);
            memset(dp,0,sizeof(dp));
            printf("%.3f
    ",dfs(m));
        }
        return 0;
    }
    
    /*
    poj  3744  求概率
      题意:侦察兵YYF要通过一条布有地雷的路,
      他从1出发,每次有p的几率前进1格,
      1-p的几率前进两个,现已知所有地雷的位置,求YYF不踩中地雷并且通过这条雷区路的的概率
      解:首先特判如果1的点是雷的话直接炸死
      易知初始化dp[0]=0;dp[1]=1;
      dp[i]=dp[i-1]*p+dp[i-2]*(1-p);
      因为i很大所以用矩阵快速幂解
      构建矩阵
      |a0,a1|*|0 1-p| =|a1 a2|
              |1  p |
    */
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N  10
    int aa[N];
    struct matrix{
        double  mat[5][5];
    };
    matrix matmul(matrix  a,matrix b) {
      int i,j,k;
      matrix c;
      memset(c.mat,0,sizeof(c.mat));
      for(i=0;i<2;i++)
        for(j=0;j<2;j++)
      for(k=0;k<2;k++)
        c.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
        return c;
    }
    matrix matpow(matrix a,int k) {
    matrix b;
    int i;
    memset(b.mat,0,sizeof(b.mat));
    for(i=0;i<2;i++)
        b.mat[i][i]=1;
    while(k) {
        if(k&1)b=matmul(a,b);
        a=matmul(a,a);
        k>>=1;
    }
    return b;
    }
    int main() {
       int n,i,k,flag;
       double p;
       while(scanf("%d%lf",&n,&p)!=EOF) {
            flag=0;
        for(i=1;i<=n;i++) {
            scanf("%d",&aa[i]);
       if(aa[i]==1)
        flag=1;
        }
        if(flag) {
            printf("%.7f
    ",0);
            continue;
        }
        sort(aa+1,aa+1+n);
        matrix a,b;
        memset(a.mat,0,sizeof(a.mat));
        a.mat[0][0]=0;
        a.mat[0][1]=1.0;
        b.mat[0][0]=0;
        b.mat[0][1]=1-p;
        b.mat[1][0]=1.0;
        b.mat[1][1]=p;
        aa[0]=1;
        for(i=1;i<=n;i++) {
            k=aa[i]-aa[i-1]-1;
          a=matmul(a,matpow(b,k));
          a.mat[0][0]=a.mat[0][1];
          a.mat[0][1]=0;
        }
        a=matmul(a,matpow(b,1));
        printf("%.7f
    ",a.mat[0][1]);
       }
    return 0;}
    








  • 相关阅读:
    HDOJ1251解题报告【字典树】
    HDOJ1305解题报告【字典树】
    HDOJ1087解题报告【动态规划】
    HDOJ1075解题报告【STL】
    HDOJ1172解题报告【暴力】
    ibatis 中调用存储过程
    后端开挂:3行代码写出8个接口!
    Go模拟浏览器登录操作代码
    Java架构师必须知道的 6 大设计原则
    easyUI时间戳转换(3种解决方法)
  • 原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410576.html
Copyright © 2011-2022 走看看