自己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的更多相关文章

  1. 2008 APAC local onsites C Millionaire (动态规划,离散化思想)

    Problem You have been invited to the popular TV show "Would you like to be a millionaire?" ...

  2. GCJ 2008 APAC local onsites C Millionaire

    时间复杂度很大.dp[i][j]表示第i轮 j这种状态的概率. #include<cstdio> #include<cstring> #include<cmath> ...

  3. Code Jam 2008 APAC local onsites Problem C. Millionaire —— 概率DP

    题意: 你有X元钱,进行M轮赌博游戏.每一轮可以将所持的任意一部分钱作为赌注(赌注为0元表示这一轮不押),赌注可以是小数的,不是一定要整数.每一轮 赢的概率为P,赢了赌注翻倍,输了赌注就没了.如果你最 ...

  4. OVS local network 连通性分析 - 每天5分钟玩转 OpenStack(132)

    前面已经创建了两个 OVS local network,今天详细分析它们之间的连通性. launch 新的 instance "cirros-vm3",网络选择 second_lo ...

  5. 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)

    上一节部署了 cirros-vm1 到 first_local_net,今天我们将再部署 cirros-vm2 到同一网络,并创建 second_local_net. 连接第二个 instance 到 ...

  6. 创建 OVS Local Network - 每天5分钟玩转 OpenStack(129)

    上一节我们完成了 OVS 的准备工作,本节从最基础的 local network 开始学习.local network 不会与宿主机的任何物理网卡连接,流量只被限制在宿主机内,同时也不关联任何的 VL ...

  7. Android local.properties 文件读取

    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6202369.html 本文出自[赵彦军的博客] 在Android Studio项目里面有个local.pro ...

  8. CocoaPods被卡住:Updating local specs repositories

    使用CocoaPods被卡住:Updating local specs repositories 使用 pod install --verbose --no-repo-update

  9. 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 * ...

随机推荐

  1. python3 BeautifulSoup模块使用

    BeautifulSoup就是Python的一个HTML或XML的解析库,可以用它来方便地从网页中提取数据.官方解释如下: Beautiful Soup提供一些简单的.Python式的函数来处理导航. ...

  2. AirtestIDE实践二:Poco框架试用

    上一篇用airtest框架做了一个梦幻西游手游的DEMO,这次看看poco的强大之处.首先安装poco:pip install pocoui 其次,把SDK集成到你家游戏中,我这直接用官网提供的一个U ...

  3. mysql新手入门随笔4

    40.子查询:出现在其他SQL语句里的SELECT语句 例如:SELECT sname,mark FROM student WHERE mark = (SELECT max(mark) FROM st ...

  4. 【WXS全局对象】Number

    属性: 名称 说明 Number.MAX_VALUE 返回JS中可表示的最大的数.它的近似值为 1.7976931348623157 x 10308. Number.MIN_VALUE 返回JS中可表 ...

  5. leetcode-组合总数III(回溯)

    组合总和 III 找出所有相加之和为 n 的 k 个数的组合.组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字. 说明: 所有数字都是正整数. 解集不能包含重复的组合.  示例 ...

  6. Python基础 之 set集合 与 字符串格式化

    数据类型的回顾与总结 可变与不可变1.可变:列表,字典2.不可变:字符串,数字,元组 访问顺序:1.直接访问:数字2.顺序访问:字符串,列表,元祖3.映射:字典 存放元素个数:容器类型:列表,元祖,字 ...

  7. Linux系统查看系统版本命令

    以下操作在centos系统上实现,有些方式可能只适用centos/redhat版本系统 uname -a |uname -r查看内核版本信息 [root@node1 ~]# uname -a Linu ...

  8. POJ 2208 Pyramids(求四面体体积)

    Description Recently in Farland, a country in Asia, a famous scientist Mr. Log Archeo has discovered ...

  9. 如何理解*p++

    后置递增运算符的优先级高于解引用运算符! *p++ 等价于 *(p++) 但是,我们*p++的求值结果不可理解为p+1指向的对象的值,而应该是p指向的对象的值. 这是由于后置++的特性引起的. *p+ ...

  10. 基于NABCD评论“探路者”Alpha版作品

    1.分析 N(Need):”为了重温贪吃蛇这一经典游戏,本组的选题定为贪吃蛇游戏,并在此基础上进行了新的创新,将普通的贪吃蛇游戏改为单词版贪吃蛇.市面上的英语单词背记软件对于那些缺少英语学习兴趣.毅力 ...