某不知名的题 - 概率DP

4 篇文章 0 订阅

两名玩家进行对战,P1拥有N点血量,P2用有M点血量。

两人均有一定概率可以打出1-6点上海,每次两名玩家进行对战的时候,伤害高的一方可以打掉伤害低的一方一点血量。

已知N,M以及两名玩家的攻击力概率。求P1是胜利的概率。

输入

多组输入,魅族输入两个整数N,M表示玩家的血量(1<=N,M<=2000)

随后输入两组浮点数每组6个浮点数,分别表示P1,P2打出1-6伤害的概率。

输出

对于每组输入输出P1的胜率(输入保留两位小数)


示例输入

5 5

1.00 0.00 0.00 0.00 0.00 0.00

0.00 0.00 0.00 0.00 0.00 1.00

示例输出

0.00

思路:我们用二维dp数组表示出p1的血量和p2的血量分别到达a和b的概率即dp[a][b],这是我们假设p1和p2赢的概率为wp1和wp2,现在有状态转移方程

dp[a][b]=dp[a-1][b]*wp2+dp[a][b-1]*wp1

但是我们没有考虑到平局的情况,假设平局概率为f对于dp[a-1][b]到达dp[a][b]可能直接p2赢也可能平一局,也或许平3局所以

dp[a][b]=dp[a-1][b]*(wp2+f*wp2+f^2*wp2+...+f^n*wp2)+dp[a][b-1]*(wp1+f*wp1+f^2*wp1+...+f^n*wp1)

提出wp2剩余一个等比数列,由前n项和且f^n趋近于0可得前n项和为1/(1-f)

dp[a][b]=dp[a-1][b]*wp2/(1-f)+dp[a][b-1]*wp1/(1-f)

以上就是状态转移方程

我们最后只需要将dp[i][m](0<=i<=n-1)相加得到最终答案

注意:dp不能直接递推到dp[i][m]当p2到达m状态时p1已经获胜,不能继续递推到下个状态。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;

double dp[2010][2010];
int main()
{
    double p1[7],p2[7];
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        double wp1=0,wp2=0,f12=0;
        for(int i=0;i<6;i++)
        {
            scanf("%lf",&p1[i]);
        }
        for(int i=0;i<6;i++)
        {
            scanf("%lf",&p2[i]);
        }
        for(int i=1;i<6;i++)
        {
            for(int j=0;j<i;j++)
            {
                wp1 += p1[i]*p2[j];
            }
        }
        for(int i=1;i<6;i++)
        {
            for(int j=0;j<i;j++)
            {
                wp2 += p2[i]*p1[j];
            }
        }
        for(int i=0;i<6;i++)
        {
            f12 += p1[i]*p2[i];
        }
        wp1/=(1-f12);
        wp2/=(1-f12);
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            dp[i][0]=(dp[i-1][0]*wp2);
        }
        for(int i=1;i<=m;i++)
        {
            dp[0][i]=(dp[0][i-1]*wp1);
        }
        for(int i=1;i<n;i++)
        {
            for(int j=1;j<m;j++)
            {
                dp[i][j]=(dp[i-1][j]*wp2+dp[i][j-1]*wp1);
            }
        }
        double ans=0;
        for(int i=0;i<n;i++)
        {
            ans += dp[i][m-1]*(wp1);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值