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

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...