算法设计与分析 实验4 动态规划法求扔鸡蛋问题

news2024/12/22 20:54:43

目录

一、实验目的

二、问题描述

三、实验要求

四、实验内容

动态规划法

算法描述

算法伪代码描述

算法复杂度分析

数据测试

二分优化的动态规划法

算法描述

二分优化:

算法伪代码

算法复杂度分析

数据测试

单调决策优化的动态规划法

算法描述

算法伪代码描述

算法复杂度分析

数据测试

空间降维优化

算法分析

算法伪代码描述

数据测试

综合分析

五、实验结论


一、实验目的

        1. 掌握动态规划算法设计思想。

        2. 掌握扔鸡蛋问题的动态规划法。

二、问题描述

        扔鸡蛋问题是计算机程序设计中的一个经典问题。从一幢楼房的不同楼层往下扔鸡蛋,用最少的最坏情况试验次数,确定鸡蛋不会摔碎的最高安全楼层。仅有一个鸡蛋供试验时,只能采用顺序查找法。有足够多的鸡蛋时,可以采用二分查找法。有多于一个但数量有限的鸡蛋时,采用动态规划方法求解。双蛋问题(two-egg problem)是本问题的一个特例,曾出现于谷歌的程序员面试题中。

        有一幢楼房高层。某人准备了N个鸡蛋供试验。他想知道鸡蛋从几层扔下不会摔碎,并确定出最高安全楼层。试验过程中,鸡蛋没有摔碎则可以继续使用,摔碎了则需要换一个鸡蛋继续试验。为保证试验成功,此人要设计一个程序,以最小化最坏情况的试验次数F(M, N)。作为一个数学抽象,本问题采用一些理想化假设:所有鸡蛋抗摔能力相同,不计重复坠地的累积损伤,且忽略试验结果的偶然性。试验成功的标准是在N个鸡蛋用完之前,精确确定最高安全楼层是哪一层。允许有鸡蛋剩余。

        如果只有N=1个鸡蛋供试验,则为了保证试验成功,只能从一层开始逐层往上试验。这相当于采用顺序查找算法,最坏试验次数F(M, 1)=M。如果一层就碎了,则最高安全楼层为0。如果M层还不碎,则最高安全楼层为M。

三、实验要求

        1. 给出解决问题的动态规划方程;

        2. 理论分析该算法的时间复杂度;

        3. 分别测试M=10000, 20000, …, 100000, N=20时以及M=50000, N=11, 12, …, 20时的算法运行时间,并分析实验结果;

        4. 依次在终端输出M=10000, N=1~20时的F(M, N)值,实验课时检查该代码,限用C或C++语言编写。

四、实验内容

动态规划法
算法描述

        动态规划的优势在于对于每一个子问题都只求解一次,而后将该结果保存,但再次对

子问题的求解时直接使用即可,这样子避免了许多子问题被重复计算多次,造成的时间复杂度较高,耗时较长的问题。

       因此,我对状态进行了如下定义:

              dpi,j 表示用i个鸡蛋可以确认j层楼的门槛层的最少操作次数

       在状态定义完成后,便要考虑动态规划的另一个条件,初始态,即边界条件,从题目描述中我们可以得知,当鸡蛋数i=1时,对于j层楼我们需要从第一层楼开始向上测试,所需要的最少操作数目为dp1,j =j,当楼层数j=0时,对于i个鸡蛋,我们需要的最少操作次数为dpi,0 =0。

       对于每一个状态,对其考虑状态转移

       对于i个鸡蛋𝑗层楼,在第𝑥层(1 ≤ 𝑥 ≤ 𝑗)扔鸡蛋时,我们用𝑝𝑥表示确定门槛层需要的操作次数。对于每个鸡蛋:

        • 若鸡蛋破碎,子问题的规模是鸡蛋数变为i - 1,楼层数变为𝑥 - 1层,其最优解为dpi-1,x-1 ,最后再加上本次的操作次数,所以操作次数 𝑝𝑥 =dpi-1,x-1  + 1;

        • 若鸡蛋没有破碎,此时子问题的规模是鸡蛋数不变,楼层数变为𝑗 - 𝑥层,其最优解为𝑑𝑝𝑖,𝑗-𝑥,最后再加上本次的操作次数,所以操作次数 𝑝𝑥 = dpi,j-x  + 1。

       但由于我们并不知道扔下去的鸡蛋是否会碎,因此我们要在两种情况的查找次数中选择最大值,即考虑最坏的情况,所以𝑝𝑥 = max(dpi-1,x-1 , dpi,j-x ) + 1

        综上分析,可以写出动态规划方程:

dpi,j = { p1 , p2 ,p3 ,……., pj }

       即                                      dpi,j=min⁡{max(dpi-1,x-1, dpi,j-x) + 1}  1<=x<=j

                                                 其中,边界条件为dp1,j =j,dpi,0 =0

       动态规划的过程实际上就是一个填表的过程,以下为模拟填表的过程:当我们要填𝑑𝑝4,6的时候,根据动态规划方程,我们需要枚举每一个扔鸡蛋的楼层𝑥(1 ≤ 𝑥 ≤ 6)作为我们的上一个状态,所有的状态中选择最小的答案即为我们的答案。

算法伪代码描述

算法复杂度分析

        对于n个鸡蛋和m层楼的跌落实验:

                时间复杂度:状态数量一共为n*m个,并且对于每个状态枚举扔鸡蛋的楼层需要O(m)的时间,一共为O(nm2)

                空间复杂度:由于所有的状态需要 O(1)的空间存储,所以空间复杂度为𝑂(nm)

数据测试

        为降低偶然性,我们对每组数据重复测试 10 次再取平均值,并利用公式T=T0*n*m2n0*m0^2 绘制理论运行时间曲线。

当M=10000, 20000, …, 100000, N=20时

楼层 m

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

操作数

14

15

15

16

16

16

17

17

17

17

实际耗时s

13.5

54.3

122.6

210.9

329.2

472.3

642.5

839.4

1072.1

1320.7

理论耗时s

13.5

54.0

121.5

216.0

337.5

486.0

662.5

864.0

1093.5

1350

        由上图所示,蓝色曲线为动态规划法实际运行时间拟合曲线,橙色曲线为动态规划法理论运行时间拟合曲线,两条曲线基本吻合,故动态规划法的时间复杂度满足𝑂(nm2)。

        当M=50000, N=11, 12, …, 20,程序无法在可接受的时间内求出答案

       由于最基本的动态规划方程,其时间复杂度仍达到了n^3级,在面对大规模数据时,需要较长的时间才能计算出来,因此算法优化就十分重要

二分优化的动态规划法
算法描述

        对于动态规划方程:

dpi,j=min⁡{max(dpi-1,x-1, dpi,j-x) + 1}   1<=x<=j

       我们可以清晰的看到,dpi,j 是一个关于楼层j的单调递增函数,但鸡蛋数i固定下来时,楼层j越高,所需要的操作数也会变多,因此,在上述转移方程中,dpi-1,x-1 项是一个随x增加而单调递增的函数,而dpi,j-x 是一个随x的增加而单调递减的函数,而我们需要求得的是,找到一个位置它的最大值是所有位置中最小的

        从上图中我们可以轻松找到那个位置,即为两个函数dpi-1,x-1, dpi,j-x 变化曲线相交的点x0即可,x0可保证两个函数的最大值最小。

        但由于dpi-1,x-1dpi,j-x 都是离散函数,我们两个函数的交点可能不是整数。所以我们选择去找离这两个函数交点左右两侧最近的整数,然后取二者更优的解作为x0。 也就是说, 我们需要找到最大的满足 dpi-1,x-1  ≤ dpi,j-x  的𝑥1,以及最小的满足 dpi-1,x-1  ≥ dpi,j-x 的𝑥2,其中能保证𝑥1 + 1 = 𝑥2。

二分优化:

        我们在所有满足条件的 𝑥 上进行二分查找。对于状态𝑑𝑝𝑖,𝑗而言, 𝑥 范围是 [1,𝑗]中的任一整数。 在二分查找的过程中,假设当前这一步我们查找到了𝑥𝑚𝑖𝑑,如果 𝑑𝑝𝑖-1,𝑥𝑚𝑖𝑑-1 ≥ 𝑑𝑝𝑖,𝑗-𝑥𝑚𝑖𝑑,那么真正的𝑥𝑜𝑝𝑡一定在 𝑥𝑚𝑖𝑑 的左侧,否则真正的𝑥𝑜𝑝𝑡在 𝑥𝑚𝑖𝑑的右侧。

算法伪代码

算法复杂度分析

        对于n个鸡蛋和m层楼的跌落实验:

                时间复杂度:状态数量一共为n*m个,由于使用的是二分查找,每个状态找特定位置x0需要O(lgm)的时间,所有时间复杂度一共为O(nmlgm)

                空间复杂度:由于所有的状态需要 O(1)的空间存储,所以空间复杂度为𝑂(nm)

数据测试

        为降低偶然性,我们对每组数据重复测试 10 次再取平均值,并利用公式T=T0*n*m*lgmn0*m0*lgm0 绘制理论运行时间曲线。

        当M=10000, 20000, …, 100000, N=20时

楼层 m

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

操作数

14

15

15

16

16

16

17

17

17

17

实际耗时ms

59.6

127.7

194.2

269.4

332.4

417.9

478.4

557.4

620.9

700.4

理论耗时ms

59.6

128.1

200.1

274.2

350.0

427.1

505.3

584.4

664.3

745.0

        当M=50000, N=11, 12, …, 20时

鸡蛋数 n

11

12

13

14

15

16

17

18

19

20

操作数

14

14

14

14

14

14

14

14

14

14

实际耗时ms

178.6

193.3

208.7

223.4

240.9

265.1

273.5

296.0

324.5

337.4

理论耗时ms

178.6

194.3

211.0

227.3

243.5

259.7

276.0

292.5

308.4

324.7

        两条曲线基本吻合,故二分优化的动态规划算法的时间复杂度满足𝑂(nm log m),曲线上升趋势也符合复杂度的分析

单调决策优化的动态规划法
算法描述

        对于动态规划方程:

dpi,j=min⁡{max(dpi-1,x-1, dpi,j-x) + 1}   1<=x<=j

        如果我们固定鸡蛋数ⅈ, 随着楼层数𝑗的增加, 状态转移方程中dpi,j-x 这一项的值也会增加, 而对于状态转移方程中dpi-1,x-1 这一项,它的值是不变的,因为它和 𝑗无关。在二分优化的过程中,我们知道dpi-1,x-1 随着𝑥单调递增,而dpi,j-x 随着𝑥单调递减,那么当𝑗增加时, dpi,j-x 对应的函数折线图在每个整数点上都是增加的, 如下图所示。 因此在dpi-1,x-1 不变的情况下, 随着𝑗增加, x0是单调递增的

       与实验2中求中间区域的最短路径相同,对于楼层j,我们寻找特定位置x0是并不需要对1~j进行二分查找,而是在之前x0的基础上进行递增查找,如此一一对应的查找,均摊下来的时间复杂度为O(1)

算法伪代码描述

算法复杂度分析

        对于n个鸡蛋和m层楼的跌落实验:

                时间复杂度: 状态变量依然是n*m个, 每个状态找扔鸡蛋的楼层𝑥𝑜𝑝𝑡均摊下来的转移时间复杂度是𝑂(1), 所以时间复杂度一共为𝑂(nm)。

                空间复杂度:由于所有的状态需要 O(1)的空间存储,所以空间复杂度为𝑂(nm)

数据测试

        为降低偶然性,我们对每组数据重复测试 10 次再取平均值,并利用公式T=T0*n*mn0*m0 绘制理论运行时间曲线。

        当M=10000, 20000, …, 100000, N=20时

楼层 m

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

操作数

14

15

15

16

16

16

17

17

17

17

实际耗时ms

3.9

10.1

12.4

16.9

24.4

28.5

29.5

31.1

36.9

40.6

理论耗时ms

3.9

7.8

11.7

15.6

19.5

23.4

27.3

31.2

35.1

39.0

        当M=50000, N=11, 12, …, 20时

鸡蛋数 n

11

12

13

14

15

16

17

18

19

20

操作数

14

14

14

14

14

14

14

14

14

14

实际耗时ms

10.1

13.9

12.2

13.7

16.0

15.2

16.1

19.2

18.9

19.2

理论耗时ms

10.1

11.0

11.9

12.8

13.7

14.6

15.6

16.5

17.4

18.3

        蓝色曲线为决策单调性优化的动态规划算法实际运行时间拟合曲线,橙色曲线为决策单调性优化的动态规划算法理论运行时间拟合曲线,实际时间在理论时间上下波动,两条曲线基本吻合,故决策单调性优化的动态规划算法的时间复杂度满足𝑂(nm)。

空间降维优化
算法分析

         对单调决策优化的动态规划法观察可以发现,状态在转移时只涉及第i−1层与第i层,第i−1层以前的状态已经不需要了,我们考虑不保存之前的状态以节省空间。为此,我们可以用两个一维数组分别表示第i−1层与第i层,从而代替整个二维数组。这样转换对于时间复杂度是没有影响的,而空间复杂度便为了O(n)。

算法伪代码描述

数据测试

        为降低偶然性,我们对每组数据重复测试 10 次再取平均值,并利用公式T=T0*n*mn0*m0 绘制理论运行时间曲线。

        当M=10000, 20000, …, 100000, N=20时

楼层 m

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

操作数

14

15

15

16

16

16

17

17

17

17

实际耗时ms

1.84

3.25

2.01

6.96

7.68

5.89

7.19

7.46

8.38

12.34

理论耗时ms

1.84

3.68

5.52

7.36

9.2

11.04

12.88

14.72

16.56

18.4

         当M=50000, N=11, 12, …, 20时

鸡蛋数 n

11

12

13

14

15

16

17

18

19

20

操作数

14

14

14

14

14

14

14

14

14

14

实际耗时ms

5.0

5.4

6.4

7.4

9.3

7.5

9.2

9.6

10.3

10.9

理论耗时ms

5.0

5.4

5.9

6.4

6.8

7.2

7.7

8.3

8.6

9.2

       将其消耗的时间与(三)中未进行空间优化的算法消耗时间进行比较,可以明显的看出,通过空间优化,程序运行的效率得到了一个较大的提升。

综合分析

        将动态规划法,通过二分优化、单调决策优化、以及降维单调决策优化的测试结果进行对比分析可以看到:

        当M=10000, 20000, …, 100000, N=20时

        当M=50000, N=11, 12, …, 20时

        从上述两个图表的消耗时间对比我们可以看出:

决策+空间dp << 二分 dp < 朴素 dp

        对于朴素动态规划算法,通过填表形式保存已求解过的状态,明显提高了算法效率,在小规模数据上速度较快,但面对大规模数据,其复杂度依旧很高,并不适用

        其次是二分优化 dp, 由于其在状态转移的时候使用的是二分查找, 所以对所选楼层的查找是𝑂(log𝑛)的复杂度, 因此对于原本需要𝑂(n)时间复杂度来查找的朴素 dp, 在算法效率上由有所提高。

        决策单调性优化 dp 利用了状态转移过程中x0的单调性, 在找当前状态的x0时不断利用前一个x0来查找, 利用了这种单调性, 使其查找的时间复杂度均摊下来是𝑂(1), 因此算法效率上对于二分查找优化 dp 又有进一步的提升

        最后是在空间上的优化,将不再需要的空间释放掉,防止内存被消耗完,并可以减少程序在搜索上消耗的时间

五、实验结论

        在本次实验中,我使用了动态规划算法对鸡蛋掉落问题进行了求解

        动态规划算法利用了子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后该子问题的求解时直接查表, 这种用空间换时间的方法使时间复杂度降低为了𝑂(𝑘𝑛2), 但结果还是不够优秀。 之后我们还提出了 3 种优化算法, 分别为: 二分优化、 决策单调性优化和降维优化。 最后对各个算法进行多次测试与比较, 在算法的运行时间上我们得出以下结果:

单调决策+降维优化 dp< 单调决策优化 dp < 二分优化 dp < 朴素 dp

        使用单调决策加降维优化的动态规划算法在终端输出M=10000, N=1~20时的F(M, N)值为:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1843889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】与【深度学习】的前沿探索——【GPT-4】的创新应用

gpt4o年费&#xff1a;一年600&#xff0c; 友友们&#xff0c;一起拼单呀&#xff0c;两人就是300&#xff0c;三个人就是200&#xff0c;以此类推&#xff0c; 我已经开通年费gpt4o&#xff0c;开通时长是 从2024年6月20日到2025年7月16日 有没有一起的呀&#xff0c;有需要的…

vue3页面传参

一&#xff0c;用query传参 方法&#xff1a; router.push({path: ‘路由地址’, query: ‘参数’}) 例子&#xff1a;a页面携带参数跳转到b页面并且b页面拿到a页面传递过来的参数 在路由router.ts配置 a页面&#xff1a; <template><div >a页面</div>…

Spatio-temporal Relation Modeling for Few-shot Action Recognition

标题&#xff1a;少样本动作识别的时空关系建模 源文链接&#xff1a;Thatipelli_Spatio-Temporal_Relation_Modeling_for_Few-Shot_Action_Recognition_CVPR_2022_paper.pdf (thecvf.com)https://openaccess.thecvf.com/content/CVPR2022/papers/Thatipelli_Spatio-Temporal_…

多目标跟踪中用到的求解线性分配问题(Linear Assignment Problem,LAP)Python

多目标跟踪中用到的求解线性分配问题&#xff08;Linear Assignment Problem&#xff0c;LAP&#xff09;Python flyfish 如果想看 C版本的&#xff0c;请点这里。 线性分配问题&#xff08;LAP&#xff0c;Linear Assignment Problem&#xff09;是一个经典的优化问题&…

虚拟机配置桥接模式

背景 因为要打一些awd比赛,一些扫描工具什么的,要用到kali,就想着换成一个桥接模式 但是我看网上的一些文章任然没弄好,遇到了一些问题 前置小问题 每次点开虚拟网络编辑器的时候都没有vmnet0,但是点击更改的时候却有vmnet0 第一步: 点击更改设置 第二步: 把wmnet0删掉 …

AD使用快捷键

1、如何实现元器件旋转45放置 在Preferences >> PCB Editor >> General中将Rotation Step&#xff08;旋转的步进值&#xff09;由90改为45&#xff0c;这样以后每次按空格键旋转器件时旋转角度为45。 2、显示网络、隐藏网络 N 3、对齐 2、设置DRC检查选项&#xf…

[17] 使用Opencv_CUDA 进行滤波操作

使用Opencv_CUDA 进行滤波操作 邻域处理操作 > 滤波操作&#xff0c;拒绝或者允许某特定频段通过如果图像某处的灰度级变化缓慢&#xff0c;那么就是低频区域&#xff0c;如果灰度级变化剧烈&#xff0c;就是高频区域邻域滤波即卷积操作形态学处理&#xff1a;膨胀&#xf…

vue小总结

知识总结 【 1 】es6 语法总结 # let 定义变量 # const定义常量 ------块级作用域---- # var 以后尽量少用&#xff0c;函数作用域var 在 JavaScript 中是函数作用域或全局作用域。而 let 和 const 是块级作用域。 // 使用 var 声明全局变量 var globalVar "Im a globa…

酸性设计震撼登场,让你眼前一亮!

说起酸性&#xff08;ACID&#xff09;&#xff0c;你会想到什么&#xff1f;”我们通常会想到酸味&#xff0c;酸设计的视觉魅力是通过图形、颜色、排版给人复古、迷幻、黑暗、叛逆的感觉&#xff0c;反复几何图形和高饱和的颜色&#xff0c;使设计非常时尚&#xff0c;非常适…

linux精通 4.1

2.1.3 http服务器实现 目的 reactor应用——webserver webclient 每次上课前 看大纲down code 复习&#xff1a; 不行啊 编译给的代码报错啊 给的最新的不是0430那一版就不行啊 reactor.c:(.text0x254): relocation truncated to fit: R_X86_64_PC32 against symbol begin de…

Unity 材质系统优化(mesh相同,图片不同,但是可以将所有的图片合成一张图集)

今天提供一个Unity材质优化的思路&#xff0c;流程是这样的&#xff0c;模型的mesh相同只是图片不同&#xff0c;我想着能不能将所有的图片合成一张图集呢&#xff0c;于是我就试着在Blender里面开搞了&#xff0c;所有的mesh相同的模型&#xff0c;共用一个材质&#xff08;图…

分支结构相关

1.if 语句 结构&#xff1a; if 条件语句&#xff1a; 代码块 小练习&#xff1a; 使用random.randint()函数随机生成一个1~100之间的整数&#xff0c;判断是否是偶数 import random n random.randint(1,100) print(n) if n % 2 0:print(str(n) "是偶数") 2.else语…

Unity3d 游戏暂停(timeScale=0)引起的deltaTime关联的系列问题解决

问题描述 游戏暂停的功能是通过设置timeScale0实现的&#xff0c;不过在暂停游戏的时候&#xff0c;需要对角色进行预览和设置&#xff0c;为了实现这个功能&#xff0c;是通过鼠标控制相机的操作&#xff0c;为了使相机的操作丝滑&#xff0c;获取鼠标操作系数乘以Time.delta…

代码大模型揭秘:从下载到推理,全流程体验StarCoder

选择模型 模型榜单 大模型的发展日新月异&#xff0c;性能强劲的大模型不断涌现&#xff0c;可以实时关注开源大模型的榜单&#xff0c;选择合适自己的大模型 开源大模型榜单 开源代码大模型榜单 模型网站 目前主流的下载模型的网站就是 huggingface 全球社区&#xff0c;…

Python - 各种计算器合集【附源码】

计算器合集 一&#xff1a;极简版计算器二&#xff1a;简易版计算器三&#xff1a;不简易的计算器四&#xff1a;还可以计算器 一&#xff1a;极简版计算器 运行效果&#xff1a; import tkinter as tk import tkinter.messagebox win tk.Tk() win.title("计算器")…

Linux系统ubuntu20.04 无人机PX4 开发环境搭建(失败率很低)

Linux系统ubuntu20.04 无人机PX4 开发环境搭建 PX4固件下载开发环境搭建MAVROS安装安装地面站QGC PX4固件下载 PX4的源码处于GitHub&#xff0c;因为众所周知的原因git clone经常失败&#xff0c;此处从Gitee获取PX4源码和依赖模块。 git clone https://gitee.com/voima/PX4-…

python学习笔记-09

面向对象编程-中 面向对象三大特征&#xff1a;封装、继承、多态。 封装&#xff1a;把内容封装起来便于后面的使用。对于封装来讲&#xff0c;就是使用__init__方法将内容封装道对象中&#xff0c;然后通过对象直接或者self获取被封装的内容。 继承&#xff1a;子继承父的属…

悬浮翻译app免费怎么操作?看完这篇文章就知道了

#高考结束该出发看世界了# 高考的钟声已落&#xff0c;是时候开启探索世界的旅程了。无论是踏上旅途&#xff0c;观看视频&#xff0c;阅读书籍&#xff0c;还是浏览网页资料&#xff0c;我们都有机会拓宽视野。 然而&#xff0c;语言常常成为我们与世界沟通的障碍。好在&…

具身智能特点及实现路线

多模态——多功能的“小脑” 人类具有眼耳鼻舌身意&#xff0c;说明对于物理世界的充分感知和理解&#xff0c;是意识和智慧的来源。而传统AI更多的是被动观测&#xff0c;主要是“看”&#xff08;计算机视觉&#xff09;和“读”&#xff08;文本NLP&#xff09;&#xff0c…

Kubernetes容器运行时:Containerd vs Docke

容器化技术笔记 Kubernetes容器运行时&#xff1a;Containerd vs Docke - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this arti…