hdu3076—概率dp

hdu3076—概率dp

标签 : 概率dp


题目链接

  • 题意:
    2个人分别有AB的血数,轮流扔骰子,数小的自减一血,平的不变,谁先到减0, 谁输,问A赢的概率。
  • 题解:
    dp[i][j]表示的是第一个人有i血,第二个人有j个血的时候1赢的概率。转移方程,假设p1是每一剧中第一个人赢的概率,p2是第二个人赢的概率,dp[i][j] 转化到dp[i-2][j]的概率是p2,dp[i][j]转化到dp[i][j-1]的概率是p1,那么 (dp[i][j] = d[i-1][j]*p2+dp[i][j-1]*p1;)
  • 注意事项:
    1. 因为是概率的问题,所以要考虑精度的问题,所以一般定义状态的时候就直接把dp[n][m]定义成最后的结果,不然如果最后的结果需要相加或者别的形式运算才能得到的话很有可能有精度的问题,刚开始定义dp[i][j]表示第一个人失去i格血,第二个人失去j格血的概率;
    2. 这个题一定是个脑残出的,m和n的输入是反的,而且输入并不保证输入的赢的概率和平的概率还有输的概率加起来等于1
    3. 这个题要注意要进行一次概率转化。通过概率转化排除平局的概率对答案的影响。
  • ac 代码和错误代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2008;
double dp[N][N];//dp[i][j]表示的是第一个人有i血,第二个人有j个血的时候1赢的概率。
double a[6],b[6];
int main()
{
    int n, m;
    while(~scanf("%d%d",&m,&n))
    {
        for(int i = 0; i < 6; i++)  scanf("%lf",&a[i]);
        for(int j = 0; j < 6; j++)  scanf("%lf",&b[j]);
        double p1, p2, ping;
        p1 = p2 = ping = 0;
        
        for(int i = 0; i < 6; i++){
            for(int j = 0; j <= 6; j++){
                //if(i==j) ping += a[i]*b[j];
                if(i>j)
                    p1 += a[i]*b[j];
                else if(i<j)
                    p2 +=a[i]*b[j];
            }
        }
       // p2 = 1-p1-ping;
        double tm = p1+p2;
        p1 = p1/tm;
        p2 = p2/tm;
        //printf("%lf %lf %lf
",p1,p2,ping);
        for(int i = 0; i <= m; i++) dp[0][i] = 0;
        for(int j = 0; j <= n; j++) dp[j][0] = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                dp[i][j] = dp[i-1][j]*p2+dp[i][j-1]*p1;
            }
        }
        printf("%lf
",dp[n][m]);
    }
    return 0;
}








/*

//下面是错误的代码,因为想一下其实每次得到的不是最后的解,那么精度会有很大问题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2008;
double dp[N][N];//dp[i][j]表示第一个人失去i格血,第二个人失去j格血的时候1赢的概率;
double a[6],b[6];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i = 0; i < 6; i++) scanf("%lf",&a[i]);
        for(int i = 0; i < 6; i++) scanf("%lf",&b[i]);
        double p = 0;
        double p2 = 0;
        double ping = 0;
        for(int i = 0; i < 6; i++){
            for(int j = 0; j < i; j++){
                if(i==j) ping = a[i]*b[j];
                else
                    p += a[i]*b[j];
            }
        }
        p2 = 1-p-ping;
      //  printf("%lf %lf
",p,p2);
       // memset(dp,0,sizeof(dp));
       for(int i = 0;i <= n; i++){
            for(int j = 0; j <= m; j++)
                dp[i][j] = 1;
       }
        dp[0][1] = p;
        dp[1][0] = p2;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                dp[i][j] = dp[i-1][j]*p2+dp[i][j-1]*p;
            }
        }
        double ans = 0;
        for(int i = 0; i < n; i++){
            ans*=dp[i][m];
        }
        printf("%lf
",ans);
    }
    return 0;
}
*/

原文地址:https://www.cnblogs.com/shanyr/p/5808231.html