学了,记录下
你被邀请到某个电视节目中去玩下面这个游戏。一开始你有x元钱,接着进行m轮赌博,每一轮,可以将所持的任意一部分作为赌注,赌注不光可以是整数,也可以是小数,一分钱不押或全押都没有关系,每一轮都有p的概率可以赢,赢了赌注就好翻倍,输了赌注就没了,如果你最后有100万以上的钱的话,就可以把钱带回家。请计算当你采取最优策略时,获得100万以上的钱并带回家的概率。 0<=p<=1.0,1<=1<=1000000,1<=m<=15 样例输入: M,p, x 输入 :1 0.5 500000 输出 0.500000(一开始九全押上) 输入: 3,0.75 600000 输出0.843750
先计算样例:
从60000中拿出2500,如果赢了,再拿出75,可以 两轮赢0.75*0.75 ,要是第二轮输了,三轮赢全堵上赢0.75*0.25*0.75
或者第一轮输了,后面两轮全赢。三轮赢0.25*0.75*0.75。
白书解析:对于赌博,因为每次都能下注的金额是无限种可能的,所以,要将无限化有限(化连续为离散)
对于最后一次赌博:
1. 本金>= 1000 000 概率为1(直接就走了)
2. 本金>=5000 00 概率为P(赢了有,输了没)
3. 本金<5000 00 概率为0 (不管输赢都没有1000 000)
最后两轮:
1.本金 >=1000 000 概率为1
2. 本金 >=7500 00 概率为:P*P(两次都输才会输2500 00+5000 00)
3. 本金 >=5000 00 概率为:P(赢一次直接走,输了必定不可能到1000 000)
4. 本金 >=2500 00 概率为:(1-P)*(1-P)必须两次都赢
5. 本金 <2500 00 概率为:0 别想了 . . . .
某个范围内,即使所持的钱数不同,最后可以带钱回家的概率也是相同的
M轮 考虑 2^M+1 种情况。因此将金额进行离散化分段处理。
设dp[r+1][i]为进行到第r+1轮,现有i段钱能赢得百万的概率?那什么是最优策略呢?在第r轮要对拿出多少去赌好呢?。
不知道要拿多少,那我们枚举吧,假设r轮要拿出j个段钱去赌
那么dp[r+1][i]=max(dp[r][i+j]*p+dp[r][i-j]*(1-p)) j=min( i,n-i);
因为i+j<=n;i-j>=0; 所以 j<=i,j<n-i;
所以最后的答案就是dp[M][X所在的段]
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN = 15;
double dp[18][(1<<MAXN)+1];//dp[i][j]代表在运行了i伦的情况下有钱数j获胜的概率
int main(){
int M,X;
double P;
scanf("%d %lf %d",&M,&P,&X);
int n = 1<<M;
dp[0][n] = 1.0;
int m=(ll)X*n/1e6;
for(int r=0;r<M;r++){ //r是赌博的轮数,0代表还没开始,M代表最后
for(int i=0;i<=n;i++){ //i是情况序号,代表百万数据的 i/2^m
int step = min(i,n-i);
double t =0.0;int pt;
for(int j=0;j<=step;j++){//从i个钱中拿出j个去赌,赢了后变i+j个,输了变i-j个,从中中出最优划分。
// if(t<dp[r][i+j]*P+dp[r][i-j]*(1-P))t=dp[r][i+j]*P+dp[r][i-j]*(1-P),pt=j; 观察最优策略
dp[r+1][i] =max(dp[r+1][i],dp[r][i+j]*P+dp[r][i-j]*(1-P)) ;
}
cout<<"dp["<<r+1<<"]["<<i<<"]="<<dp[r+1][i]<<"="<<dp[r][i+pt]<<"*"<<P<<"+ "<<dp[r][i-pt]<<"*"<<(1-P)<<","<<pt<<endl;
}
}
printf("%.6f\n",dp[M][m]);
return 0;
}