共有 $n$ 层楼,$m$ 个鸡蛋,没碎的鸡蛋可以重复使用
求最少要多少次可以求出鸡蛋摔碎的临界楼层?
题目链接: 鸡蛋的硬度
很久以前就听说过这个题了,据说是谷歌面试题,也是一个动态规划的经典问题
但是一直都没有尝试去做
看了李永乐老师的讲解之后试着写了一下
有一些边界问题没有细考虑,但是对上了这个表
时间复杂度:$O(n^{2}m)$
C++代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1010, INF = 1e9;
int n, m;
int f[N][N]; // f[i][j]表示共i层楼j个鸡蛋时最少要试几次保证能找到临界点
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
{
// 楼层数为i时,鸡蛋数量为1时,需要从低到高遍历,共i次
f[i][1] = i;
for(int j = 2; j <= m; j ++)
{
// 要求最小值时,先反向赋一个很大的值
f[i][j] = INF;
// 遍历鸡蛋扔在的k层的情况
for(int k = 1; k <= i; k ++)
/*
设临界值为t
f[k - 1][j - 1]为鸡蛋碎了,t在[1, k]这个区间中,共k层,剩余j - 1个鸡蛋
f[i - k][j]为鸡蛋未碎,t在[k + 1, i]这个区间中,共i - k层,剩余j个鸡蛋
在两种情况中取较大值(考虑最坏情况)加上本次,更新f[i][j]
*/
f[i][j] = min(f[i][j], max(f[k - 1][j - 1], f[i - k][j]) + 1);
}
}
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
printf("%6d", f[i][j]);
puts("");
}
return 0;
}
原来b站视频底下那个评论是你😂2333
其实可以证明当m>log n的时候答案就是log n,所以这个算法的最高时间复杂度为O(n^2 log n)
def optimum(n,m):
if n==0:
return 0
if n==1:
return 1
if m==1:
return n
times=[]
for x in range(1,1+n):
maximum=max(optimum(n-x,m),optimum(x-1,m-1))+1
times.append(maximum)
times.sort()
return times[0]
lists=[]
#二维列表
height=20
quantity=2
times=optimum(height,quantity)
print(times)
python写的代码,如果数字过大无法运行,请问是怎么回事呢?
写成递归的话复杂度太高啦
感谢滑稽大佬
B站游客~感觉钻了一个逻辑上的空子,虽然结果是对的,不知道你是不是考虑到了
在这里
如果k=1或者k=i的时候,会出现0楼层的情况,分别对应了扔在第一层就碎了、仍在最高层还没碎,这两种情况下,意味着不需要下次投掷,所以值是0,而刚好全局数组未初始化的默认值就是0
有些边界问题挺费脑子的,我一般都是随便改改代码看看有没有对上样例,结果对了就是对了(手动滑稽)
还是要养成良好的数组初始化习惯,使代码更健壮👍
蓝桥杯其实也考过,好像是砸手机那题,我们学长跟我说的,那个时候好多人看不懂题目以为是二分hh。。
我之前以为俩鸡蛋就只能扔两次=,=
时间复杂度:应该是O((n^3)*m)吧?
是 n^2 * m 啊,状态空间是O(n^2),状态转换的时间复杂度是O(m)。
哦豁 群友