?吗来出得做你,目题的型类么什是这说不我果如

文章目录

  • 高楼落球
    • 题目描述
    • 问题说明
    • 解题思路
    • 代码
    • 后记
  • 金币分配
    • 题目描述
    • 解题思路
    • 代码
    • 后记
  • 导语

高楼落球

题目描述

⚠ 警告:高空抛物会危及他人生命,并将使你面临受指控的风险。请不要高空抛物。

这也是一道特别经典的题:一百层楼和两个玻璃小球的问题。为了严谨地描述问题,题目描述会异常地长。

现有一栋一百层的高楼及两个一模一样的易碎的玻璃球。存在正整数 n ≤ 100 n \leq 100 n100,使得下面的描述成立:

从第 n n n 层楼将球扔下,球会破碎;从第 ( n − 1 ) (n-1) (n1) 层楼将球扔下,球不会破碎。

你不知道 n n n 的值是多少。你能确保楼下无人路过,并将通过动手实验来求出它的值。你可以在任意的楼层扔下球,然后得知球是否破碎。未破碎的球可以从任意的楼层再次扔下;已破碎的球无法再扔。从任意楼层扔下一个球并得知球是否破碎的过程称为一次“测试”。

你将设计一个通用的计划,这个计划包含恒定次数的、有限次数的测试,不论 n n n 的值是多少,这个计划总是能求出 n n n 的值。

求解:符合条件的计划所包含的测试次数的最小值 m m m

问题说明

这里以一个球及三层楼为例,进一步说明问题。

如果只有一个球和三层楼,显然应该先在第1层测试,然后是第2层,最后是第3层。假设小球在第1层测试之后就碎了,你也因此求得了 n n n 的值,你实际上只做了一次测试,实验就可以停止了。但是你的计划是“先在第1层测试,然后是第2层,最后是第3层”。所以你的计划所包含的测试次数是3次,而不是1次。

可以证明,如果减少上述计划中的测试次数,那么就存在符合条件的 n n n,使得这个计划无法确定 n n n 的值。比如说,如果你的计划是“先在第2层测试,然后是第3层”,这个计划所包含的测试次数是2次,但是当 n = 1 n=1 n=1 时,这个计划无法确定出 n = 1 n=1 n=1

解题思路

h = f ( m , b ) h=f(m, b) h=f(m,b),其中 m m m 为一个计划的测试次数, h h h 为这个计划可以解决的问题的楼的最大高度, b b b 为球的数量。即,用 b b b 个球做 m m m 次测试的计划,可以解决最多 h h h 层楼的问题。

直接考虑两个球的情况似乎太难了。先考虑 b = 1 b=1 b=1 的情况。因为只有一个球,所以只能从第1层楼开始测试,一层一层楼向上走、扔球做测试。所以
f ( m , 1 ) = m f(m,1)=m f(m,1)=m
然后再考虑 b = 2 b=2 b=2,测试次数为 m m m 的情况。
先将第一个球从第 t t t 层楼扔下:
a)如果第一个球碎了,那么剩下的测试次数为 m − 1 m-1 m1,剩下的球的数量为 1 1 1。因此
f ( m , 2 ) ≥ f ( m − 1 , 1 ) f(m,2) \geq f(m-1,1) f(m,2)f(m1,1)

这种情况下,第二个球只能是从第1层开始逐层向上测试。所以第二个球所能测试的楼层范围应为 [ 1 ,      f ( m − 1 , 1 ) ] \left[1,\;\; f(m-1,1)\right] [1,f(m1,1)]

b)如果第一个球没碎,则可以将第 t t t 层视为“第0层”,剩下的测试次数为 m − 1 m-1 m1,剩下的球的数量为 2 2 2。因此
f ( m , 2 ) ≥ t + f ( m − 1 , 2 ) f(m,2) \geq t+f(m-1,2) f(m,2)t+f(m1,2)

这种情况下,后续测试所能测试的楼层范围应为 [ t + 1 ,      t + f ( m − 1 , 2 ) ] \left[t+1, \;\; t+f(m-1,2)\right] [t+1,t+f(m1,2)]

如果我们令
t = f ( m − 1 , 1 ) + 1 t = f(m-1,1)+1 t=f(m1,1)+1
那么上述两种情况对应的后续的可测试楼层的区间就是相邻的,即上述情况对应的后续的可测试楼层的范围为
[ 1 ,      1 + f ( m − 1 , 1 ) + f ( m − 1 , 2 ) ] \left[1, \;\;1+f(m-1,1)+f(m-1,2)\right] [1,1+f(m1,1)+f(m1,2)]。即
f ( m , 2 ) = 1 + f ( m − 1 , 1 ) + f ( m − 1 , 2 )      . . . . . .      ( 1 ) f(m,2)=1+f(m-1,1)+f(m-1,2) \;\;......\;\;(1) f(m,2)=1+f(m1,1)+f(m1,2)......(1)

又有
f ( m , 1 ) = m      . . . . . .      ( 2 ) f(m,1)=m \;\;......\;\;(2) f(m,1)=m......(2)
f ( 1 , b ) = 1      . . . . . .      ( 3 ) f(1,b)=1 \;\;......\;\;(3) f(1,b)=1......(3)
利用 (1)(2)(3) 式,可以得出 f ( m , 2 ) f(m,2) f(m,2) 的通项公式。

原题转化为求下列不等式的最小整数解:
f ( m , 2 ) ≥ 100 f(m,2)\geq 100 f(m,2)100

(1) 式的推导过程也可以迁移到多于两个球的情形。可以得到
f ( m , b ) = 1 + f ( m − 1 , b − 1 ) + f ( m − 1 , b ) f(m,b)=1+f(m-1,b-1)+f(m-1,b) f(m,b)=1+f(m1,b1)+f(m1,b)
有这样的递推公式,就可以通过动态规划求解。 f ( m , b ) f(m,b) f(m,b) 实际上是关于 m m m b b b 次多项式,所以 h = f ( m , b ) = Θ ( m b ) h=f(m,b)=\Theta(m^b) h=f(m,b)=Θ(mb)。空间复杂度最低可以为 Θ ( h 1 / b ) \Theta(h ^{1/b}) Θ(h1/b):使用一个长度为楼层数的数组,在不断增大 b b b 的同时,更新这个数组即可。时间复杂度为 Θ ( b   h 1 / b ) \Theta(b\,h ^{1/b}) Θ(bh1/b)

代码

printf("14\n");

后记

具体答案是多少不重要。这题的解题思想也是先从最简单的子问题(一个球或者一层楼)开始考虑的。其实上面的推导过程对更多的球也是类似的,可以得出这类问题的通解。虽然上面的题解是用数学方法算出了通项公式,但是这种“先解决规模较小的子问题”的思想对动态规划题是十分重要的。

另外,题解也没有直接设 m m m 等于什么什么东西。而是换了一个角度,研究“一定的测试次数和一定数量的球能解决什么规模的问题”。这种问题转化的思想很妙。

所以要学好数学啊。

金币分配

题目描述

这是一道十分经典又简单的题目,你甚至可以口算出来。

五个海盗分配 100 枚金币。他们依次提出分配方案。如果有超过一半(不含一半,计其本人)的人同意这个方案,那么这个方案有效,分配将按这个方案进行;否则方案无效。提出无效方案的人会被杀掉,然后由下一个人提出方案。

他们五个人中每个人都比你们学校的年级第一聪明。他们每个人都想在保住性命的前提下取得尽可能多的金币。因为他们太聪明了,所以第一个人提出了最佳的有效方案。

求解:第一个人提出的最佳方案。如果有多种可能的方案,输出其中一种。

解题思路

直接考虑五个人的情况似乎太难了。

只剩4号和5号的情况:只要5号不同意,4号就一定会死,然后5号必定能得100金币。因此4号必定不会让人数减少到两人。

只剩3、4、5号的情况:因为4号必定不会让人数减少到两人,所以4号必定同意3号的方案。因此,若由3号来分配,3、4、5号分别会得到100、0、0枚金币。

只剩2、3、4、5号的情况:只要2号死掉,3号就可以得到100金币;而2号不死掉,也不可能给3号多于100的金币。所以2号没法争取到3号的同意。2号只能争取4、5号的同意。2号可以思考一下3号的最佳分配方案(3、4、5号分别得100、0、0),他只要给2、3、4、5号分别分配98、0、1、1枚金币即可。因为如果4或者5号不同意,他们连1枚金币都拿不到。这样做,2号就花了最少的钱收买了足够的人。

5个人都在的情况:类比四个人的情况,只要1号给出的金币比2号给出的多1枚,1号就能得到一个人的同意。所以1号只要思考一下2号的最佳分配方案(2、3、4、5号分别得98、0、1、1),找出2号的分配方案中得利最少的2个人,然后收买那两个人,剩下的留给自己就行了。因此1号的分配方案是97、0、1、2、0。这样,3、4号都会同意1号的方案。如果他们不同意1号,由2号分配时,他们得到的金币会少1枚。(97、0、1、0、2也是可以的)

当人数足够多(多于三个)时,要求得最佳分配方案,只需要考虑下一个人的最佳分配方案。找出下一个人的最佳分配方案中获益最小的若干个人,然后拿出更多的金币收买他们就行了。这就是这类问题的通解,可以用动态规划来做。每次都要找出获益最小的若干个人,因此要排序,时间复杂度为 Θ ( n 2 log ⁡ n ) \Theta(n^{2} \log{n}) Θ(n2logn)。只需要一个长度为总人数的数组来记录中间过程、另一个数组用于排序,所以空间复杂度为 Θ ( n ) \Theta(n) Θ(n)

代码

printf("97 0 1 2 0\n");

后记

从人数较少的时候开始思考会简单很多。这就是由规模较小的子问题推及规模更大的问题的过程。

导语

介绍两道动态规划的题。

这两道题的参数实际上已经固定了,这两题也可以完全不用动态规划。但如果题目中的参数可变,动态规划应该是最好的解决方案。

这里面的解题思想对于我这样的菜鸡来说太重要,所以记录下来。

你可能感兴趣的:(小小算法题,动态规划,算法,高楼,金币,题解)