Small input 13 points |
Solve C-small
|
Large input 16 points |
Solve C-large
|
Problem
You have been invited to the popular TV show "Would you like to be a millionaire?". Of course you would!
The rules of the show are simple:If you win the bet, your total amount of money increases by the amount you bet. Otherwise, your amount of money decreases by the amount you bet.
Given M, P and X, determine your probability of winning at least $1000000 if you play optimally (i.e. you play so that you maximize your chances of becoming a millionaire).
Input
The first line of input gives the number of cases, N.
Each of the following N lines has the format "M P X", where:
Output
For each test case, output one line containing "Case #X: Y", where:
Answers with a relative or absolute error of at most 10-6 will be considered correct.
Limits
1 ≤ N ≤ 100
0 ≤ P ≤ 1.0, there will be at most 6 digits after the decimal point.
1 ≤ X ≤ 1000000
Small dataset
1 ≤ M ≤ 5
Large dataset
1 ≤ M ≤ 15
Sample
In the first case, the only way to reach $1000000 is to bet everything in the single round.
In the second case, you can play so that you can still reach $1000000 even if you lose a bet. Here's one way to do it:
题意:最开始你有x元钱,要进行M轮赌博。每一轮赢的概率为P,你可以选择赌与不赌,如果赌也可以将所持的任意一部分钱作为赌注(可以是整数,也可以是小数)。如果赢了,赌注将翻倍;输了赌注则没了。在M轮赌博结束后,如果你持有的钱在100万元以上,就可以把这些钱带回家。问:当你采取最优策略时,获得100万元以上的钱并带回家的概率是多少。
类型:动态规划&离散化思想
分析:由于每一轮的赌注是任意的,不一定为整数,因而有无限种可能,所以即便想穷竭搜索也无从着手。但如果能化连续为离散,那么可能便也是有限的了。具体如下:假设前M-1轮的赌博后,还持有x'元。对于最后一轮,考虑的情况有3种。如果x' >= 100万,则没有必要再赌了即最后一轮赢的概率为0;如果50<= x' < 100万,只要参与赌博并且赌注 >= 50万则有赢的概率为P;如果x' < 50万,那么无论是否参与最后一轮的赌博,压的赌注是多少赢的概率必为0。我们不妨看一下倒数第二轮与最后一轮的关系,设在倒数第二轮时持有的钱为x。如果x >= 100万,赢的概率为1;如果x < 25万,即便最后两轮赌博都赢了总钱数必小于100万,所以赢的概率为0;否则,只要选择参与至少一轮赌博并且赌注至少25万则有赢得概率。假设倒数第二轮的赌注为y(y = 0 或 y >= 25万),则最后一轮持有的钱x' = (x + y)或x' = (x - y)。而倒数第二轮考虑的情况具体可以分为5种。综上,当参与M轮赌博时所需考虑的情况总共有2^m + 1种,可以通过dp解决。定义一个二维dp数组,dp[i][j] := 参与第i轮赌博,持有的钱所在模块为j并且采取最优策略时赢的概率。初始化:dp[n][1 << m] = 1,状态转移方程dp[i][j] = max(P * dp[i + 1][j + k] + (1 - P) * dp[i + 1][j - k] / 0 <= k <= min(j, n - j) )。时间复杂度O(m*2^2m)。
#include <iostream> #include <memory.h> #include <algorithm> #include <cstdio> using namespace std; int M , X; double P; double dp[2][(1 << 15) + 1]; void solve() { int n = 1 << M; double *pre = dp[0] , *nxt = dp[1]; memset(pre , 0 , sizeof(double) * (n + 1)); pre[n] = 1.0;//因:模块n对应的资金>= 100万 for(int r = 0 ; r < M; r++) { for(int i = 0 ; i <= n ; i++) { int step = min(i , n - i);//避免i + j > n double t = 0.0; for(int j = 0 ; j <= step ; j++) t = max(t , P * pre[i + j] + (1 - P) * pre[i - j]);//进行m轮赌博,最小赌资应为 100万/n nxt[i] = t;//以模块i的资金进行r + 1轮赌博,赢的最大概率 } swap(pre , nxt); } int i = X * n / 1000000;//资金X所在模块 printf("%.6lf\n" , pre[i]); } int main() { cin >> M >> P >> X; solve(); return 0; }