自己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. hdu1455Sticks(经典dfs+剪枝)

    Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  2. 使用Docker部署java web项目

    在国内可能会有源下载失败问题,docker安装失败, 这里提供docker离线安装包如有需要可以进行下载 docker离线安装包下载 ##本文环境使用centos 7 进行部署. #1安装docker ...

  3. 【Linux 运维】查看网络连接状态信息之netstat和ss命令详解

    一.netstat 常用命令详解 通过man netstat可以查看netstat的帮助信息: netstat 命令:用于显示各种网络相关信息,如网络连接,路由表,接口状态,无效连接,组播成员 等等. ...

  4. Ext JS 6学习文档-第3章-基础组件

    Ext JS 6学习文档-第3章-基础组件 基础组件 在本章中,你将学习到一些 Ext JS 基础组件的使用.同时我们会结合所学创建一个小项目.这一章我们将学习以下知识点: 熟悉基本的组件 – 按钮, ...

  5. nodejs基础学习

    一:复制官网的代码,建立一个简单的服务器 const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; ...

  6. 软工2017第六周团队协作——个人PSP

    10.20 --10.26本周例行报告 1.PSP(personal software process )个人软件过程. 类型 任务 开始时间                结束时间 中断时间 实际用 ...

  7. Calculation PartⅡ

    GitHub/object-oriented 误删内容--周末修复

  8. ubuntu软件管理apt与dpkg

    目前ubuntu系统主要有dpkg和apt两种软件管理方式两种区别如下 1.dpkg是用来安装.deb文件,但不会解决模块的依赖关系,且不会关心ubuntu的软件仓库内的软件,可以用于安装本地的deb ...

  9. 利用SqlServer的作业定时清除过期数据

    有时候我们的数据库中可能会有那么些存放动态数据的表,比如一些每天定时发出的消息通知信息等数据.这些数据我们只需要临时保存,一些老旧的数据需要定时去清除掉,不然时间一长的话单表数据堆积非常严重.导致数据 ...

  10. winform Form窗体和UserControl用户空间嵌入Panel容器并填充

    private void sbtbflList_Click(object sender, EventArgs e) { ucxmflList ucfl = new ucxmflList();//用户控 ...