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 * ...
随机推荐
- mysql新手进阶02
云想衣裳花想容,春风拂槛露华浓. 若非群玉山头见,会向瑶台月下逢. 现在有一教学管理系统,具体的关系模式如下: Student (no, name, sex, birthday, class) Tea ...
- python里pickle模块
Pickle模块用于将复杂的文件转化为二进制的文件 pickle模块一般是在源代码里面含有较大的字典或者列表等复杂文件时,我们如果将文件直接写在源代码里面,这样会使得代码很冗余,并且源代码文件所占空间 ...
- Python类对象
python类对象 python类对象支持两种操作:属性引用和实例化. 属性引用 使用 Python 中所有属性引用所使用的标准语法: obj.name. 有效的属性名称是类对象被创建时存在于类命名空 ...
- Laxcus大数据管理系统2.0(7)- 第五章 数据构建
第五章 数据构建 在数据处理过程,我们经常会遇到这样的情况:大多数时候,用户最初输入的数据会含有大量无意义的.杂乱的信息,需要经过提炼.收集.汇总等一系列手段,才能产生有意义和用户可识别的数据内容:当 ...
- 浅谈PCA
最近在回顾PCA方面的知识,发现对于之前的很多东西有了新的理解,下面和大家分享下我的一些个人的理解 1.我们为什么要用PCA,它能解决我什么问题? PCA(Principal Component An ...
- AC 自动机——多模式串匹配
网站上的敏感词过滤是怎么实现的呢? 实际上,这些功能最基本的原理就是字符串匹配算法,也就是通过维护一个敏感词的字典,当用户输入一段文字内容后,通过字符串匹配算法来检查用户输入的内容是否包含敏感词. B ...
- 2.azkaban3.0安装
安装规划安装azkban1.安装配置数据库2.下载安装web server3.安装mulit executor4.安装azkaban插件AZKABAN参数安装出现的问题 安装规划 IP 角色 端口 1 ...
- Linux查看物理CPU个数,核数,逻辑CPU个数;内存信息
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...
- BZOJ 4361 isn 容斥+dp+树状数组
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4361 题意概述: 给出一个长度为N的序列A(A1,A2...AN).如果序列A不是非降的 ...
- Mishka and Contest(模拟水题)
Mishka started participating in a programming contest. There are nn problems in the contest. Mishka' ...