GCJ2008 APAC local onsites C Millionaire
自己Blog的第一篇文章,嗯...
接触这道题,是从《挑战程序设计竞赛》这本书看来的,其实头一遍读题解,并没有懂。当然现在已经理解了,想想当初可能是因为考虑两轮的那张概率图的问题。于是决定把自己的理解整理一下。
题面
(喜欢看原题的同学!这里来!GCJ官网直接配送哦!)
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:
- Before the game starts, the host spins a wheel of fortune to determine P, the probability of winning each bet.
- You start out with some money: X dollars.
- There are M rounds of betting. In each round, you can bet any part of your current money, including none of it or all of it. The amount is not limited to whole dollars or whole cents.
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.
- After all the rounds of betting are done, you get to keep your winnings (this time the amount is rounded down to whole dollars) only if you have accumulated $1000000 or more. Otherwise you get nothing.
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).
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
题意
你被邀请去玩一个赌博游戏。一开始你有美刀X,接着进行M轮赌博。每一轮你可以拿出自己的一部分钱作为赌注,可以不是整数。当然,你也可以选择全押或者不押都可以。每一轮有P的概率你会赢,赢了赌注就会翻倍,输了赌注就没有了。最后你如果持有1 000 000美刀以上的钱的话,就可以把这些钱带回家。请计算当你采取最优策略时,获得1 000 000美刀以上并带回家的概率。
§ 1 难点
你会十分绝望的发现,每轮当前的钱和赌注都可以是小数,这直接使得暴力枚举的方法无用。
§ 2 离散化!
我们先从简单入手,分析一下最后一轮下会出现的情况。
- 如果你持有$1 000 000及以上的钱,那这轮就没必要赌了,因为你可以保证你有1的概率把钱带回家。
- 如果你持有$500 000及以上的钱,那不妨全押上。这样你有P的概率,可以让手头的钱翻倍,那就超过$1 000 000,可以带回家了。但若你不全押,赢了却不一定能达到$1 000 000,输了就是肯定带不回去的(所以输的情况其实和全押是一样的)。因而全押更划得来, 有P的概率可以带回家。
- 如果你持有不到$500 000,即使这一轮你全押并且赢了,也达不到$1 000 000。有0的概率可以带回家。
这样一共是三种情况。你会发现,即使当前持有金额它可能是小数,但是在一段段连续的区间里,带回家的概率都是一样的,这样我们就把当前你持有的金额这个无限的空间,映射到三段简单易见的范围中去了,达到了离散化的效果。
同样,最后两轮时,我们会分为五种情况考虑:0 ~ $250 000, $250 000 ~ $500 000, $500 000 ~ $750 000, $750 000 ~ $1 000 000, $1 000 000 ~ +INF
为什么是这样呢?
我们这个时候可以先列出一个递推式:
- Probability(next round)sum = max{ P * Probability(this round)sum + stake + (1 - P) * Probability(this round)sum - stake }
- 其中 Probabilitysum 表示某一轮开始手头持有金额为sum的概率,stake表示当前这一轮的赌注。
这个式子就不必解释了,接下来我们看下面一张图。
- 它就是按照我们当前的例子画的,左边线段表示最后两轮概率的情况,右边线段表示最后一轮概率的情况。不同的颜色的线在右边线段上框出的范围表示左边线段上的点按照上式计算概率时会涉及到的范围。
- 注意到边界0和$1000 000(超过$1000 000概率为1,没有必要研究),这个范围是不能超过边界的。
- 并且,左边线段上我们多取了两个点,是右边线段相邻两个点的中点。
你会发现,右边线段 0 ~ $1 000 000 这个区间被分为四段,而这四段可以涉及到的范围都是不相同的。比如说 $750 000 ~ $1 000 000 这段最多能涉及到最后一轮时 $500 000 ~ $1 000 000 的范围,而 $500 000 ~ $750 000 涉及可以涉及到最后一轮 0 ~ $1000 000 的范围。(可以多画几个点看一看)
显然这四段同一段里面的点概率都是相同的。
因此最后两轮被分为了5种情况。
所以说,最后M轮的时候,会被分为(2M+1)种情况。且每次多增加的情况间的分界点就是上一轮两个分界点的中点。
这样就只需要考虑这(2M+1)种情况就可以了,于是达到了离散化的效果。
§ 3 参考代码
就是《挑战》里的写法,已经在GCJ上通过了Small和Large的。(就是Large实在跑得有点慢,不过没有Time Limit)
// Millionaire
// GCJ 2008 APAC local onsites C #include <cstdio>
#include <cstring>
#include <algorithm>
const int MAXR = << + ;
int N, M, X;
double P, dp[][MAXR]; int main() {
freopen("C-large-practice.in", "r", stdin);
freopen("C-answer.out", "w", stdout);
scanf("%d", &N);
int i, k, j, l, r;
for (k = ; k <= N; k++) {
scanf("%d%lf%d", &M, &P, &X);
r = << M;
double *prv = dp[], *nxt = dp[];
memset(prv, , sizeof(double) * (r + ));
prv[r] = 1.0;
for (i = ; i < M; i++) {
for (j = ; j <= r; j++) {
int Lim = std::min(j, r - j);
nxt[j] = 0.0;
for (l = ; l <= Lim; l++) nxt[j] = std::max(nxt[j], P * prv[j + l] + ( - P) * prv[j - l]);
}
std::swap(prv, nxt);
}
i = (long long)X * r / ;
printf("Case #%d: %.6lf\n", k, prv[i]);
}
fclose(stdin);
fclose(stdout);
return 0;
}
另外,有问题的童鞋欢迎提问~
谢谢大家!
GCJ2008 APAC local onsites C Millionaire的更多相关文章
- 2008 APAC local onsites C Millionaire (动态规划,离散化思想)
Problem You have been invited to the popular TV show "Would you like to be a millionaire?" ...
- GCJ 2008 APAC local onsites C Millionaire
时间复杂度很大.dp[i][j]表示第i轮 j这种状态的概率. #include<cstdio> #include<cstring> #include<cmath> ...
- Code Jam 2008 APAC local onsites Problem C. Millionaire —— 概率DP
题意: 你有X元钱,进行M轮赌博游戏.每一轮可以将所持的任意一部分钱作为赌注(赌注为0元表示这一轮不押),赌注可以是小数的,不是一定要整数.每一轮 赢的概率为P,赢了赌注翻倍,输了赌注就没了.如果你最 ...
- OVS local network 连通性分析 - 每天5分钟玩转 OpenStack(132)
前面已经创建了两个 OVS local network,今天详细分析它们之间的连通性. launch 新的 instance "cirros-vm3",网络选择 second_lo ...
- 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)
上一节部署了 cirros-vm1 到 first_local_net,今天我们将再部署 cirros-vm2 到同一网络,并创建 second_local_net. 连接第二个 instance 到 ...
- 创建 OVS Local Network - 每天5分钟玩转 OpenStack(129)
上一节我们完成了 OVS 的准备工作,本节从最基础的 local network 开始学习.local network 不会与宿主机的任何物理网卡连接,流量只被限制在宿主机内,同时也不关联任何的 VL ...
- Android local.properties 文件读取
转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6202369.html 本文出自[赵彦军的博客] 在Android Studio项目里面有个local.pro ...
- CocoaPods被卡住:Updating local specs repositories
使用CocoaPods被卡住:Updating local specs repositories 使用 pod install --verbose --no-repo-update
- Failure to find xxx in xxx was cached in the local repository, resolution will not be reattempted until the update interval of nexus has elapsed or updates are forced @ xxx
问题: 在linux服务器上使用maven编译war时报错: 16:41:35 [FATAL] Non-resolvable parent POM for ***: Failure to find * ...
随机推荐
- unity实现框选效果
思路: 在uinity中既可以将屏幕坐标转换为世界坐标,也可以将世界坐标转换为屏幕坐标.这样的话我们就可以通过判断物体在世界坐标转换为平幕坐标是否在鼠标框选的矩形区域坐标内,来判断物体是否在框选范围. ...
- Siki_Unity_2-1_API常用方法和类详细讲解(上)
Unity 2-1 API常用方法和类详细讲解(上) 任务1&2:课程前言.学习方法 && 开发环境.查API文档 API: Application Programming I ...
- [JSON].exists( keyPath )
语法:[JSON].exists( keyPath ) 返回:[True | False] 说明:检测指定键名路径是否存在 示例: Set jsonObj = toJson("{div:{' ...
- some Commands OF CONSOLE
不可避免地使用console,一旦与电脑打交道:入口就是help,而很多行就直接过掉了,却不能看到需要的地方,在那里停下来,实际是需要使用more less grep等 在windows中,使用di ...
- 解析范式(1NF-4NF)
亲爱的盆友们~又是新的一年,你,准备好新的学习计划了吗~?是读书100本,还是考上5个证?嘛~不管怎么说,角落里那一堆蒙尘的计划表好像在昭示着这仍然是一个充满朝气又艰难的9102年呢!总之,先把#技本 ...
- 孵化器使用Office365的场景及收益
- 开源自动驾驶仿真平台 AirSim (2) - 编译 AirSim
AirSim 的官方 Github: https://github.com/Microsoft/AirSim 对于 Unreal Engine 来说,AirSim 其实是作为一个插件存在,说白了就是把 ...
- solidity python 签名和验证
注意,以太坊智能合约里面采用的是公钥非紧凑类型 def gen_secrets_pair(): """ 得到公钥和私钥 :return: ""&quo ...
- c#基类继承
[ 塔 · 第 三 条 约 定 ] 编写一个多边形作为基类(成员:定点数)抽象方法(子类实现):体积.边长 正三角形类:成员 边长 长方形类:成员 长宽 using System; using Sys ...
- TCP系列06—连接管理—5、TCP fastopen(TFO)
一.TFO背景 当前web和web-like应用中一般都是在三次握手后开始数据传输,相比于UDP,多了一个RTT的时延,即使当前很多应用使用长连接来处理这种情况,但是仍然由一定比例的短连接,这额外多出 ...