GCJ millionnare 概率DP

题目大意

开局持有本钱 X,进行 M 局赌局,每局有 P 的概率使所下赌注翻倍,1-P 的概率赌注全输,押注没有要求,可以全压或者不压,也可以压任意数量包括小数的赌注,要求在赌局结束时如果持有10万元及以上的钱就可以获胜。计算在采取最优策略时,获胜的概率。

输入 

按照 M P X 的顺序输入。

1,0.5,500000

输出

0.50000

 

分析

由于赌注的押注是任意的,这意味着有无限种可能性,表面看来无法利用穷举,不妨先进行几次模拟来探寻一下规律。

当只进行一轮时,本金与获胜关系为:

①X >=100万,必胜,概率 = 1;

②100万 >= X >= 50万 ,刚好获胜的情况是,设投入 Y (Y <= X )万元,则 (X-Y) + 2Y = 100 → X + Y = 100 , 当X = 50 时,Y = 50 概率 = P;当X > 50 时,只要至少投入100 - X 万元 ,那么一定有P的概率获胜,所以在这个区间内,获胜的最优概率都是一样的。(实际上就是连续数学的离散化,举几个例子就能确认)。

③50万 >= X >= 0,就算全押入,也必输,概率 = 0。

发现在一定区间内,本金与获胜概率存在对应关系。

当只进行二轮时,本金与获胜关系为:

先不急讨论,来看一下,不管第一轮本金多少,是输了还是赢了,最后的所持钱数仍然会属于进行一轮时的三个区间内,那么就可以得到一个倒推关系:若上一轮的押注翻倍,或者失败,则下一轮的本金 = 上一轮本金 ± 押注 ,而下一轮的本金与获胜关系的概率已经求出,那么 可以得到  该轮本金与获胜关系 = P * 下一轮本金与获胜概率(1) + (1-P) * 下一轮本金与获胜概率(2)。

(1) 表示 上一轮押注获胜下一轮本金 = 上一轮本金 + 押注 存在自己的获胜概率P1,那么总概率为 P * P1;

(2) 表示 上一轮押注失败, 下一轮本金 = 上一轮本金 - 押注 存在自己的获胜概率P2,那么总概率为 (1-P) * P2;

举个例子:第一轮有本金 X = 75 万,若投入 25 万,那获胜概率为 (押注赢)P* (下一轮本金所在区间的概率)P(75 + 25);

或者 押注失败(1 - P)* (下一轮本金所在区间的概率)P(75 - 25)。

P(75) = P * P(75 + 25) + (1-P) * P(75 - 25) (两种情况的概率是相加,因为都属于75进行的押注操作)

那么显然,有了递推关系后可以考虑动态规划,而且我们可以发现 进行轮数 M 与 本金所分成的区间关系为 n = 2^M + 1;

规定 dp[i][j] 表示第 i 轮 本金处于第 j 区间的获胜概率 ,则 dp[i][j] = P * dp[i][j + k] + (1 - P) * dp[i][j - k]。  0 =< k <= min(i,n-i).

k其实表示押注后,若赢钱,那么相当于本金所处的区间变化了,并且是向本金区间增大或者减小的方向变化,且变化的上下限不超过min(i,n-i) (防止数组越界),注意要从0开始,及0的时候表示什么都不押。

下面给出代码:
 

#include
#include
#include
#include
using namespace std;
const int maxn = 15;
int m,x;
double p;
double dp[2][(1<>m>>p>>x;
	return;
}

int main()
{
	input();
	solve();
	return 0;
}

 

你可能感兴趣的:(GCJ millionnare 概率DP)