微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

hdu 3076 ssworld VS DDD概率DP

题目描述

题面

题目大意:两个人A、B,血量分别为HA、HB,轮流掷骰子,每个人掷骰子的6种情况都有一定的概率,谁点数小谁扣一滴血,没血了就输了,问A赢的概率。

坑点:血量输入是反的,而且听说总概率还可能不等于1。-_-||

题解

dp[i][j]表示A有i血,B有j血A赢的概率。概率正推,dp[x][0]=1.0(x!=0),然后dp[i][j]=dp[i][j-1]*p1+dp[i-1][j]*p2,其中p1为每次A赢的概率,p2位每次B赢的概率。

注意平局不贡献答案,我们要预先处理出正确的p1和p2,忽略平局的影响。(说个类比,就是生物上的某基因型致死然后问你某个生物是某个基因型的概率)

然后由于double有爆空间的风险,直接滚动第一维即可。但是我想到一个问题,这样赋初值时让dp[0][0]=dp[1][0]=1.0,当i和j都为0时的状态的值不就错了吗?但是我们枚举状态时根本不会去算i=0或j=0的情况,所以根本没有这个转移,总之zenzen没问题。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>

using namespace std;

int n,m;
double dp[2][2002],a[7],b[7];

int main(){

    while(~ scanf("%d%d",&m,&n)){

        for(int i = 1; i <= 6; i++)  scanf("%lf",&a[i]);

        for(int i = 1; i <= 6; i++)  scanf("%lf",&b[i]);

        double p1 = 0.0,p2 = 0.0,sum;

        for(int i = 0; i <= m; i++)
            dp[0][i] = dp[1][i] = 0.0;

        for(int i = 1; i <= 6; i++)
            for(int j = 1; j <= 6; j++){
                if(i > j)  p1 += a[i] * b[j];
                if(i < j)  p2 += a[i] * b[j];
            }

        sum = p1 + p2;
        p1 /= sum;
        p2 /= sum;

        int x = 0;
        dp[0][0] = dp[1][0] = 1.0;

        for(int i = 1; i <= n; i++){
            x ^= 1;
            for(int j = 1; j <= m; j++)
            dp[x][j] = dp[x][j-1] * p1 + dp[x^1][j] * p2;
        }

        printf("%.6lf\n",dp[x][m]);
    }

    return 0;
}

原文地址:https://www.jb51.cc/javaschema/282288.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐