概率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;}








原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410576.html