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