扔鸡蛋问题 动态规划大法
之前有一篇文章“扔鸡蛋问题”,写的是指定鸡蛋个数在指定楼层,求最优解。里面列举了二分法、平方根法和解方程法,但是,如果鸡蛋个数和楼层数是待定的,那这三种方法都搞不定了。所以,这里又得引申出新的方法“动态规划大法”
首先说一下什么是动态规划。动态规划,英文Dynamic programming,是求解决策过程最优化的数学方法。动态规划的大致思路是把一个复杂问题转化成一个分阶段逐步递推的过程,从简单的厨师状态一步一步递推,最终得到复杂问题的最优解。
动态规划分为两步:
1. 寻找状态转移方程式2. 利用状态转移方程式自下而上的求解问题
那如何找到 状态转移方程式呢?我们可以把M层楼/N个鸡蛋的问题转化成一个函数F(M,N),其中,楼层M和鸡蛋N是两个参数,而函数的值则是最优解的最大尝试次数。假设我们第一个鸡蛋扔出的位置在第X层(1<=x<=m),会出现两种情况:
1.第一个鸡蛋没碎
那么剩下的资源是 M-X 层楼,N个鸡蛋,可以转变为下面的函数:
F(M-X,N) + 1 ,1<=X<=M
2.第一个鸡蛋碎了
那么剩下的资源是 X-1 层楼,N-1个鸡蛋,可以转变成下面的函数:
F(X-1,N-1) + 1 ,1<=X<=M
也就是说,我们要求出M层楼/N个鸡蛋,最大尝试次数的最小值的解,可以用下面的状态转移方程式:
F(M,N) = Min( Max(F(M-X,N) + 1 , F(X-1,N-1) + 1) ) ,1<=X<=M
好了,第一步的“寻找状态转移方程式”搞定了,接下来是第二步“利用状态转移方程式来自下而上的求解”。根据动态规划的思想,我们需要从一个鸡蛋一层楼的最优尝试次数,一步一步推导后续的状态。
为了更加形象具体的表述推导的过程,这里使用表格法
鸡蛋个数\楼层个数 | 一层楼 | 二层楼 | 三层楼 | 四层楼 |
一个鸡蛋 | 1 | 2 | 3 | 4 |
二个鸡蛋 | 1 | |||
三个鸡蛋 | 1 |
一个鸡蛋的情况下,最大尝试次数就是楼层的个数;楼层数固定是一层,那最大尝试次数就是恒定1。
当2个鸡蛋,2层楼的情况下,我们就需要代入状态转移方程式了
F(2,2) = Min( Max( F(M-1,N) + 1 , F(X-1 , N-1) + 1) ) = Min( Max( F(2-X,2) + 1 , F(X-1 , 2-1) + 1) ),1<=X<=2
因为X的取值是1或者2,我们需要对X的值逐一尝试:
当X=1时,
F(2,2) = Max( F(2-X,2) + 1 , F(X-1 , 2-1) + 1)
= Max( F(2-1,2) + 1 , F(1-1 , 2-1) + 1) = Max( F(1,2) + 1 , F(0 , 2-1) + 1) = Max(1+1 , 0+1)= 2
当X=2时,
F(2,2) = Max( F(2-X,2) + 1 , F(X-1 , 2-1) + 1)
= Max( F(2-2,2) + 1 , F(2-1 , 2-1) + 1) = Max(F(0,2) + 1 , F(1,1) + 1)= Max(0+1 , 1+1)= 2
所以,无论第一个鸡蛋是从第一次扔,还是从第二层扔,结局都是尝试2次。
鸡蛋个数\楼层个数 | 一层楼 | 二层楼 | 三层楼 | 四层楼 |
一个鸡蛋 | 1 | 2 | 3 | 4 |
二个鸡蛋 | 1 | 2 | ||
三个鸡蛋 | 1 |
以此类推,可以得到所有的内的值
鸡蛋个数\楼层个数 | 一层楼 | 二层楼 | 三层楼 | 四层楼 |
一个鸡蛋 | 1 | 2 | 3 | 4 |
二个鸡蛋 | 1 | 2 | 2 | 3 |
三个鸡蛋 | 1 | 2 | 2 | 3 |
OK,我们使用表格大法,理解了动态规划的第二步操作。那么,我们在程序里,如何用代码实现呢?
public class ThrowEggs {public static void main(String[] args) {int floorNum = 4;int eggNum = 3;System.out.println(getMinSteps(floorNum, eggNum));}public static int getMinSteps(int floorNum, int eggNum) {if (floorNum < 1 || eggNum < 1) {return 0;}// 定义表格int[][] table = new int[floorNum+1][eggNum+1];// 表格初始化for(int m=1;m<=floorNum;m++){// 楼层for(int n=1;n<=eggNum;n++){ // 蛋个数table[m][n] = m;}}for(int n=2;n<=eggNum;n++){for(int m=1;m<=floorNum;m++){// 枚举N个鸡蛋,在M层楼层,所有的可能,如果初始化的值大于计算的值,则计算的值替换原坐标的值for(int k=1;k<=m;k++){table[m][n] = Math.min(table[m][n], 1 + Math.max(table[m-k][n], table[k-1][n-1]));}}}return table[floorNum][eggNum];}
}
上面的代码是实现了动态规划的需求,但是,时间复杂度是O(N * M * M),又涉及到了二维数组,所以空间复杂度是O(M * N)。时间复杂度不好优化了,空间复杂度倒是可以再优化一下,根据 F(M,N) = Min( Max(F(M-X,N) + 1 , F(X-1,N-1) + 1) ),每一次自下而上的求解,都只和上一层和本层的值有关联,所有我们可以只需保存上一层的结果。
public static int getMinStepsOptimized(int floorNum, int eggNum) {if (floorNum < 1 || eggNum < 1) {return 0;}// 上一次的结果集,鸡蛋数-1,floorNum楼层 的最优尝试次数int[] preCache = new int[floorNum+1];// 当前的结果集,当前鸡蛋数,floorNum楼层数,最优尝试次数int[] currentCache = new int[floorNum+1];// 初始化currentCache的值for(int i=1;i<=floorNum;i++){currentCache[i] = i; }for(int n=2;n<=eggNum;n++){// 把上一次的值,传递给preCachepreCache = currentCache.clone();// 重新初始化currentCachefor(int i=1;i<=floorNum;i++){currentCache[i] = i;}for(int m=1;m<=floorNum;m++){// 枚举N个鸡蛋,在M层楼层,所有的可能,如果初始化的值大于计算的值,则计算的值替换原坐标的值for(int k=1;k<=m;k++){currentCache[m] = Math.min(currentCache[m], 1 + Math.max(preCache[k-1], currentCache[m-k]));}}}return currentCache[floorNum];}
扔鸡蛋问题 动态规划大法相关推荐
- 高楼扔鸡蛋问题 - 动态规划+反推演绎
对于高楼扔鸡蛋问题,本文尝试反其道而行之:首先描述一个普适的高楼扔鸡蛋问题,然后利用动态规划法解决扔鸡蛋次数的问题,最后由获取次数的答案反推出扔鸡蛋的方法. 这种由次数答案反推出方法的演绎方式令人有点 ...
- 每日一道算法题:高楼扔鸡蛋问题(动态规划问题)
题目是这样:你面前有一栋从 1 到N共N层的楼,然后给你K个鸡蛋(K至少为 1).现在确定这栋楼存在楼层0 <= F <= N,在这层楼将鸡蛋扔下去,鸡蛋恰好没摔碎(高于F的楼层都会碎,低 ...
- 扔鸡蛋问题-动态规划
这个问题是一个印度朋友问我的. 已知有e个鸡蛋,f层楼.问题是尽可能少的尝试,找出扔出鸡蛋不破的最高的楼层. 最开始我的思路是,如果只有一个鸡蛋,f层楼,毫无疑问,只能从一楼到二楼到三楼...依次尝试 ...
- java动态规划鸡蛋问题_动态规划系列/高楼扔鸡蛋问题.md · lipengfei/fucking-algorithm - Gitee.com...
# 经典动态规划问题:高楼扔鸡蛋 今天要聊一个很经典的算法问题,若干层楼,若干个鸡蛋,让你算出最少的尝试次数,找到鸡蛋恰好摔不碎的那层楼.国内大厂以及谷歌脸书面试都经常考察这道题,只不过他们觉得扔鸡蛋 ...
- 动态规划与数学方程法解决楼层扔鸡蛋问题
1.问题描述 两个软硬程度一样的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事.有座100层的建筑,用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置,可以摔碎两个鸡蛋,求给出一个最佳策略 ...
- 彻底搞懂-扔鸡蛋问题-方程-动态规划
1.题目: 2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度,比如鸡蛋在第9层没有摔碎而在第10层摔碎了,那么鸡蛋不会摔碎的零界点就是9层,如何用最少的尝试次数,测试出鸡蛋不会摔碎的临界点? 2. ...
- 高楼扔鸡蛋问题-经典动态规划
文章目录 1. 高楼扔鸡蛋 2. 猜数字大小 1. 高楼扔鸡蛋 给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑. 已知存在楼层 f ,满足 0 <= f &l ...
- 动态规划之扔鸡蛋(或手机)问题
引入 有2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度.比如鸡蛋在第9层没有摔碎,在第10层摔碎了,那么鸡蛋不会摔碎的临界点就是9层. 问:如何用最少的尝试次数,测试出鸡蛋不会摔碎的临界点? 分 ...
- 扔鸡蛋问题-方程-动态规划
参考:程序员小灰 https://blog.csdn.net/weixin_40564421/article/details/78988078 题目:2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬 ...
最新文章
- 全文搜索引擎Elasticsearch,这篇文章给讲透了
- 如何ping端口_复刻smartbits的国产网络性能测试工具minismb-如何配置Ping报文
- 使用Intent启动组件
- scikit-image基本用法(上)
- mysql索引及优化
- LINUX文件的压缩与打包
- vim中括号自动补全
- node访问oracledb的环境搭建
- Xshell 一款很养眼的配色方案推荐
- 微博上一些有用的话(四)
- OneNote for win10 登录不了
- 网卡添加VLAN TAG
- html embed自动播放,html embed标签怎么用
- Granted QOS different to Requested QOS
- 未明学院:量化金融训练营开始报名,成为兼具数据分析技能+项目实战经验的复合型人才!
- 【C语言】exit(0)与exit(1)有什么区别
- java中package_java 中 package 是什么?
- 写C#代码时用到的中文简体字 、繁体字 对应的转化 (收藏吧)
- Pro-Level Photography for Graphic Designers 平面设计师专业摄影教程 Lynda课程中文字幕
- 基于标准反向传播算法的改进BP神经网络算法(Matlab代码实现)
热门文章
- oracle tz_offset 参数,无法根据TZ_OFFSET的值进行数据访问
- set the request's mode to 'no-cors' to fetch the resource with CORS disa
- 10大领域5大过程47子过程快速记忆
- 生成10位随机数(PHP)
- 使用java中Scanner,Randon,ArrayList完成一个随机点名系统
- 关于开展上海市2022年度高新技术企业认定管理相关工作的通知
- 2020年全国高新企业认证名单统计
- 利用apache+wsgi运行你的django网站 - Open Idea - 博客大巴
- Windows上鲜为人知的三款黑马软件,款款深入人心
- WindowsAPI关机、重启