测试次数(动态规划)
转自:传送门
这道题是去年第九届蓝桥杯B组的第四道题。
下面先放上题目:
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
注意:需要填写的是一个整数,不要填写任何多余内容。
下面是大佬的思路:
思路1:动态规划。
首先,我们再来看一遍题目的问题:从每个厂家抽样3部手机参加测试,某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?什么叫最佳策略,什么又叫最坏运气下(这里最多是匹配最坏运气说的)?翻译一下就是:摔死了3部手机并且测试到最后一次才能测出耐摔指数所需要的最少测试次数。
好了,那么我们下面要想办法找出这个最少的测试次数。这里我们可以设这个测试次数为k次,3部手机一共测试k次可以测出耐摔指数。既然有k次机会,我们不妨就把第1部手机先从第k层楼摔下去。如果第1部手机摔死了,那么第2部手机剩下k-1次机会,可以从1~k-1层来测试。如果第1部手机没摔死,那么它还剩下k-1次机会,那我们下次就可以从第k+(k-1)层楼摔。如果它这一次摔死了,那么第2部手机还有k-2次机会,就可以从k+1~k+(k-1)-1层来测试。如果第1部手机在第k+(k-1)层摔下来后仍旧活下来了,那么它还有k-2次机会,在下次就可以从第k+(k-1)+(k-2)层摔。以此类推,一定可以在k次内测出耐摔指数。
那么有人就要说了,你这里只说了2部手机,可是我们有3部手机啊。其实情况是一样的,假如我们有n部手机m层楼,第1部手机在第k层摔死了,那么接下来要测试的就是n-1部手机k-1层楼的情况,如果没摔死,就测试n部手机m-k层楼的情况(人会有主观意识觉得楼层越高越容易摔死,但是那不一定,手机也有可能到1000层都摔不死呢,所以测试情况的时候我们可以只看层数,k+1~m和1~m-k是一样的)。
综上所述,我们可以推出动态转移方程:dp[i][j]表示i部手机j层楼的最少测试次数,dp[i][j]=max(dp[i-1][k-1],dp[i][j-k])+1,k∈[1,j-1](这里取max是因为i部手机j层楼有dp[i][j]次测试机会,我们必须确保在这个次数内所有情况的耐摔指数都要能被测出来,如果取了较小的那个,次数多于它的情况就没法确保被测试出来)。我们一开始在给dp数组初始化的时候,可以全部初始化为它的最坏情况,j层楼的最坏测试次数是j次,就是每层楼都要摔一次,那么我们这里用了最佳策略后,次数就应该小于等于这个值,方程就可以变化为:dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1),k∈[1,j-1]。
参考:传送门
代码:
#include <bits/stdc++.h>
using namespace std;
int dp[5][1005];
void solve(int phone,int floor)
{
for(int i=1;i<=phone;i++)
for(int j=1;j<=floor;j++)
{
dp[i][j]=j; //i部手机在j层摔坏的最坏次数为j次
}
for(int i=2;i<=phone;i++)
for(int j=1;j<=floor;j++)
for(int k=1;k<j;k++)//从第k层摔下
{
dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1);
}
}
int main()
{
solve(3,1000);
printf("%d\n",dp[3][1000]);
return 0;
}
另一种思路:手算。
让我们继续……n部手机m层楼要在最少的k次测试中测出耐摔指数,因为我们事先并不知道这个耐摔指数到底是多少,也就是说这m层楼的每一层楼(每一个耐摔指数)的情况都要能在这k次中测试出来,于是问题可以转化成:n部手机k次测试最多可以测出多少层楼。
先数字小一点,用2部手机来分析好了。老样子,第1部先从第k层摔,死了就第2部从1~k-1层测试,这种情况显然不是最多的。那么如果第1部手机完好无损,它还有k-1次机会,下次可以从第k+(k-1)层摔,这里我们第1次摔就测试了k层楼,如果第2摔也没问题那么我们就测试了k+(k-1)层楼了,既然要求最多可以测出的楼层,按照这个思路,自然是每次摔下去都没死才能测到的最多,于是可以得出式子:
能测出的最多楼层要大于等于题目给出的楼层m就能求出这个次数k了:
2部手机的情况很好理解,接下来我们来分析3部手机k次测试的情况,稍微复杂一点点。根据上面的推导,我们知道2部手机k-1次机会的话可以测出层楼。现在3部手机,第1部手机从第层摔下,如果摔死了,那么就是剩下的2部手机对1~层的测试,如果没摔死,那么就是从第层摔,和上面是差不多的道理啦,然后得出式子:
题目给的是1000层,那么得出k最小为19。
参考:传送门