Code Jam 2008 APAC local onsites Problem C. Millionaire 概率DP

你有X元钱,进行M轮赌博游戏。每一轮可以将所持的任意一部分钱作为赌注(赌注为0元表示这一轮不押),赌注可以是小数的,不是一定要整数。每一轮 赢的概率为P,赢了赌注翻倍,输了赌注就没了。如果你最后持有至少1000000元钱的话,就可以把钱全部带走。要求计算在采取最优策略时,获得至少 1000000元钱的概率。

数据范围:

0<=P<=1

1<=X<=1000000

1<=M<=15


题目说可以投入小数,我们肯定不能直接算,那是无穷的。我们要分块处理。

对于最后一轮,如果我们金钱为10w,我们不需要再赌了,直接放弃,胜率为1

如果我们5w-10w,我们就要放手一搏,全部压上。

如果小于5w,那么就是GG


同理倒数第二轮,我们分了2.5w,5w,7.5w,10w四种情况。GG,赢两局,赢一局,直接胜利.

对于n轮,我们就是(1<<n)-1种情况,我们对于这些情况来处理。

对于第i轮,我们如果到达了第j种情况。我们可以选择投入多少钱呢。

就是投入第1中情况的钱/第二种,一直到第j种。

如果我们赢了,P*dp[i+j],i+j是因为我们当前i,投入j取赌博,剩下i-j,那个j胜利了,双倍返还2j。i-j+2j,也就是i+j.

如果我们输了,就是(1-p)*dp[i-j]。

所以相加即可。

就是本轮到达当前模块的胜率。

当本轮所有模块全部结束后,我们进行下轮,这个时候就是利用这次的胜率在求下轮的,所以用滚动数组即可


#include <iostream>


using namespace std;
int m;
double p,x;
double dp[2][(1<<16)+1];
int main()
{
    cin>>m>>p>>x;
    int mokuai=1<<m;
    double *pre=dp[0];//这样使用滚动数组很方便,因为第i轮,只收到第i-1轮胜率的影响。
    double *next=dp[1];
    pre[mokuai]=1.0;//意思就是在最后一个模块时,我们赌注整理为1.因为已经超了
    for(int l=0;l<m;l++)//每一轮赌注
    {
        for(int i=0;i<=mokuai;i++)//到达当前模块
        {
            double maxx=0.0;
            for(int j=0;j<=i&&i+j<=mokuai;j++)  //我们拿出j模块的钱来赌博
            {
                maxx=max(maxx,p*pre[i+j]+(1-p)*pre[i-j]);//胜了我们是得到i-j +2*j,也就是i+j的钱。败了我们得到i-j的钱
            }
            next[i]=maxx;
        }
        swap(pre,next);
    }
    int i=x*mokuai/1000000;
    cout<<pre[i]<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值