测试次数(蓝桥杯)

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值