x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
注意:需要填写的是一个整数,不要填写任何多余内容。
分析:
该题需要使用递推的方法求解,不能使用贪婪算法求解。(因为无法确定最佳策略,需要对每种情况进行比对才能确定)
- 如果我们有1部手机,塔高为n层。只有一部手机,我们只能从第一层往上测试(如果从上往下,一旦手机摔坏了,我们没有手机进行测试)。在最坏的运气下,我们需要测试n次。
- 如果我们有2部手机,塔高为n层。我们可以不用从第一层开始往上测试,因为当我们摔坏一部手机后,还有一部可以用来进行测试。这时就要考虑最佳策略了,应该从哪层开始测试更好?
- 如果n=2,不管我们从哪层开始测试,在最坏的运气下,都需要测试2次。
- 如果n=3,我们可能会想到最佳策略是从中间第2层开始。在最坏的运气下,需要测试2次。
- 如果n=4或者n更大,我们无法知道从哪层开始是最佳策略,因此要遍历从每一层开始测试的情况,找出测试次数最多的(即在最坏的运气下),在这些结果中找出最少的(即采用最佳策略)。
如果n=4,其中tab(x,y)表示用x个手机测试y层。
最后得到递推公式:(f1[n]表示1个手机,有n层楼,采用最佳策略,在最坏的运气下的测试次数;f2[n],f3[n]分别表示有2部手机和3部手机)。
f2[n]=min(for i in n (max(1+f2[n-i],1+f1[i-1])));
f3[n]=min(for i in n (max(1+f3[n-i],1+f2[i-1])));
#include<iostream>
#include<algorithm>
#include<climits>
using namespace std;
const int N = 1000;
int f1[N + 1], f2[N + 1], f3[N + 1]; //手机数为1,2,3时,对应各层的测试次数
int main(){
//1部手机
for (int i = 1; i <= N; i++){
f1[i] = i;
}
//2部手机
for (int i = 1; i <= N; i++){
int ans = INT_MAX;
//尝试1到i若干种方案,每种方案记录次数最大,最终记录所有方案中次数最小
for (int j = 1; j <= i; j++){ //从j层开始扔
//1.好的 2.坏了
int _max=max(f2[i - j] + 1, f1[j - 1] + 1);
ans = min(ans, _max);
}
f2[i] = ans;
}
//3部手机
for (int i = 1; i <= N; i++){
int ans = INT_MAX;
//尝试1到i若干种方案,每种方案记录次数最大,最终记录所有方案中次数最小
for (int j = 1; j <= i; j++){ //从j层开始扔
//1.好的 2.坏了
int _max = max(f3[i - j] + 1, f2[j - 1] + 1);
ans = min(ans, _max);
}
f3[i] = ans;
}
cout << f3[N] << endl;
system("pause");
return 0;
}