挑战程序设计 Millionaire

  Millionaire (2008 APAC local onsites C)

假设游戏开始时,你有X元钱,可进行M轮竞猜。每一轮可以将所持的任意

一部分钱作为赌注,赌注不光是整数,也可以是小数。一分钱不押或全押

都可以。每一轮都有P的概率可以赢,赢了赌注就会翻倍,输了赌注就没了,

如果你最后持有1000,000元以上的钱就可以将这些钱带回家。请计算当你

采取最优策略时,获得1000,000元以上的钱并带回家的概率。


限制条件

0<= P <= 1.0

1<= X <= 1000,000

Small

1<= M <= 5

Large

1<= M <= 15

开始分析这个题目时,看到最优策略时,脑子里就闪过动态规划和贪心算法,

动态规划和贪心算法是解决最优解问题的两大常用策略。

遇到问题,我们首先应该先从简单场景考虑,然后再推到复杂场景,最后再

推出通用规律,也就是递推公式,或表达式。

以此题为例,我们以最简单的一轮竞猜为例,那么情形就比较清楚了,当我们

手里有超过1000,000元钱时,我们赢钱回家的概率为1,而根据赢钱翻倍的规则,

如果手里刚好超过[500,000元-1000,000)元钱,刚好是个左闭右开区间,在这种情况

下要想赢钱回家,必须将手里的钱押一轮,才有可能赢钱回家,假设押的钱为A,

押完后剩下的钱为B,那么:

  • A + B = X
  • 2A + B >= 1000,000
  • 500,000<= X <1000,000

可推出 :

  • 1<= A < 1000,000
  • 0 <= B < 500,000

无论A具体为多少元钱,这一轮要求必须赌赢才能赢钱回家,而赢的概率为P,故

这种情形下,赢钱回家的概率为P。

如果手里的钱不足500,000时,即便是把所有的钱都押上,且赌赢了,翻倍后也不足

1000,000,所以这种情况下赢钱回家的概率为0。

       相对于只有一轮时的情形,当还有两轮时,情况就复杂多了,其实仔细分析可以人为是

在只有一轮时,每种情况再一分为二,当然手里超过1000,000元钱的情况就不用再一分为

二了,所以只剩下两轮时,共有5种情况。

      由上面简单情形的分析,我们可以推算出当M大于2时,共有2^M+1种情况。

再仔细分析,会发现动态规划适用于解决该问题,动态规划通常可以分为4个步骤:

  1. 描述最优解结构
  2. 递归定义最优解的值
  3. 按自底向上的方式计算最优解的值
  4. 由计算出的结果构造一个最优解

下面省去了动态规划详细分析过程,直接上程序,引用挑战程序设计大赛

#include "stdafx.h"
#include <iostream>

using namespace std;

int min(int a, int b)
{
	if(a <= b)
		return a;
	else
		return b;
}
double max(double a, double b)
{
	if(a >= b)
		return a;
	else
		return b;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int M;//竞猜轮数
	int X;//初始资金
	double P = 0.0;//竞猜成功的概率
	cout<<"输入竞猜轮数"<<endl;
	cin>>M;
	cout<<"输入初始资金"<<endl;
	cin>>X;
	cout<<"成功概率"<<endl;
	cin>>P;

	double dp[2][(1<<15)+1];
	int n = 1<<M;

	double *pre = dp[0];
	double *nxt = dp[1];

	memset(pre,0,sizeof(double)*(n+1));
	pre[n] = 1.0;
	for(int r = 0; r < M; r++)
	{
	    for(int i = 0; i <=n ; i++)
	    {
		    int jub = min(i,n-i);
		    double t = 0.0;
		    for(int j =0; j <= jub; j++)
		    {
		        t = max(t,P*pre[i+j]+(1-P)*pre[i-j]);
		    }
		    nxt[i] = t;
		}
		swap(pre,nxt);
	}
	int i = (long long)X*n/1000000;
	cout<<pre[i]<<endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值