Millionaire(2008 APAC local onsites c) 概率dp

题意:最开始你有x元钱,要进行M轮赌博。每一轮赢的概率为P,你可以选择赌与不赌,如果赌也可以将所持的任意一部分钱作为赌注(可以是整数,也可以是小数)。如果赢了,赌注将翻倍;输了赌注则没了。在M轮赌博结束后,如果你持有的钱在100万元以上,就可以把这些钱带回家。问:当你采取最优策略时,获得100万元以上的钱并带回家的概率是多少。
samples:
input:
M = 1, P = 0.5, X = 500000
output:
0.500000
input:
M = 3, P = 0.75, X = 600000
output:
0.843750

类型:动态规划&离散化思想
连续性是本问题的一大特点。每一轮可押的金钱不一定是整数,因而有无限种可能,所以无法穷竭搜索。
分析如下:
假设前M-1轮的赌博后,还持有x‘元。对于最后一轮,考虑的情况有3种。如果x‘ >= 100万,则没有必要赌下去的必要;如果50<= x‘< 100万,只要参与赌博并且赌注 >= 50万则有赢的概率为P;如果x‘< 50万,那么无论是否参与最后一轮的赌博,压的赌注是多少赢的概率必为0。
Millionaire(2008 APAC local onsites c) 概率dp_第1张图片
现在考虑一下最后两轮的情况,最后二轮考虑的情况具体可以分为5种。设在倒数第二轮时持有的钱为x‘‘。如果x‘‘>= 100万,赢的概率为1;如果x‘‘< 25万,即便最后两轮赌博都赢了也无济于事,所以赢的概率为0;否则,只要选择参与至少一轮赌博并且赌注至少25万则有获胜概率,具体获胜概率与持有的资金有关。
Millionaire(2008 APAC local onsites c) 概率dp_第2张图片
综上,可以发现,当参与M轮赌博时所需考虑的情况总共有2^m + 1种,某个范围中,即使所持的钱数不同,最后可以带钱回家的概率也是完全一样的。可以通过dp解决。
定义一个二维dp数组,dp[i][j] 表示参与第 i 轮赌博,持有的钱所处阶段为 j (阶段数为0~2^m,共2^m + 1个阶段)并且采取最优策略时赢的概率。
本题是一个 倒推 的过程,初始化:dp[n][1 << m] = 1(即在最后一轮时,处在最后一个阶段,也就是资金已经大于100W)
状态转移方程:
dp[i][j] = max(dp[i][j], P * dp[i + 1][j + k] + (1 - P) * dp[i + 1][j - k] )。
0 <= k <= min(j, n - j)    k是可以增长的阶段数
学到的方法:对于难题找不到入手点的时候,尽可能的选择最简单的情况开始分析,再看稍微复杂一点的,思考是否存在相应的联系,避免一点思绪都没有。

代码:

#include 
#include 
using namespace std;
#define M 1000000
typedef long long ll;
int n;
int m, x;
double p;
double dp[2][1 << 15 + 1];
void slove()
{
	n = 1 << m; 
	fill(dp[1], dp[1] + n, 0);
	dp[1][n] = 1.0;
	for (int k = 0; k < m; k++) //枚举第几轮
	{
		for (int i = 0; i <= n; i++) // 枚举所有阶段
		{
			double t = 0.0;
			for (int j = 0;; j++) //可以增长的阶段数
			{
				//j是可以增长的阶段数,不能超过当前所处的阶段(此时为全押)
				if (i + j > n || i - j < 0) break;
				t = max(t, p*dp[(k + 1) & 1][i + j] + (1 - p)*dp[(k + 1) & 1][i - j]);//运用滚动数组
			}
			dp[k & 1][i] = t;
		}
	}
	int ans = (ll)x * n / M; //判断在哪一个范围中
	//根据m的奇偶性来判断处在哪一个数组中  
	printf("%.6f\n", dp[(m - 1) & 1][ans]);
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> m >> p >> x;
		slove();
	}
	system("pause");
	return 0;
}

参考博客:
https://blog.csdn.net/liujc_/article/details/47256243

你可能感兴趣的:(挑战程序设计)