题目描述
X 星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
X 星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的 222 楼。
如果手机从第 777 层扔下去没摔坏,但第 888 层摔坏了,则手机耐摔指 =7=7=7。 特别地,如果手机从第 111 层扔下去就坏了,则耐摔指数 =0=0=0。 如果到了塔的最高层第 nnn 层扔没摔坏,则耐摔指数 =n=n=n。
为了减少测试次数,从每个厂家抽样 333 部手机参加测试。
某次测试的塔高为 100010001000 层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
思路:
一开始没理解透题意,果然后面的题,看出来一个easy的答案就可以直接排除了
最优化问题,考虑贪心或dp
先分析一下题目,随便一层扔下去,手机坏了,说明耐摔指数小于k,但不能说明具体是多少
如果现在没有其他手机了,那肯定测不出具体的手机耐摔系数了,所以,当手机数为1的时候,不能随便扔,只能从低到高一层一层的测试。手机多的时候这显然不是最佳策略
如果手机没坏,手机数量不变,显然可以再从上面挑一层扔,缩小可能的系数范围
归纳一下,从第k层扔下去,有两种情况:
1.手机碎了,那就说明耐摔指数一定小于k,那么要测0~k-1层
2.手机没碎,那就说明耐摔系数大于等于k,那么要测k+1~n层
并且发现,100~110和10~20两个层段,楼层数相同的情况下,给定相同手机数,两层的最佳策略的摔手机次数是一样的!
比如,两部手机,100~110,最佳策略应该先从中间105扔,运气最差应该是系数为103or104(碎了最麻烦,如果没碎,可以从108继续扔缩小一半区间),那么需要从100依次尝试到104,一共6次;从10~20,最佳策略也应从中间扔,也就是15层,运气最差应该是14or13,需要从10到11,12,13,14,依次尝试,一共也是6次,可以看出只与中间夹的层数有关,
也就是说存在子结构,动态规划
设dp[i][j]为,有j部手机,夹层数为i做测试,从中间第k层扔下,最优策略下的次数
1.手机碎了,dp[i][j]=dp[k-1][j-1]+1
2.手机没碎,dp[i][j]=dp[i-k][j]+1
每次运气最差,也就是说每次都正好选到测试次数最多的那个中间层k,最优策略,即所有最差测试里面最少次数的那个!这个地方也容易错!而且这里错了很冤!
得到递推式为:dp[i][j]=min(dp[i][j],max(dp[i-k][j]+1,dp[k-1][j-1]+1)+1);
注意边界条件,i=0,j=0时应该都是0,并且一部手机的时候层数就是最少取值
#include <bits/stdc++.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <cstring>
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <string>
#define MAX 1010
#define INF 0x3f3f3f3f
#define EXP 1e-9
#define DEUBG 0
#define MOD 1000000007
using namespace std;
typedef long long ll;
int n,m,t,k;
string s;
int dp[MAX][MAX];
int main(){
n=1000;
m=3;
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<=n;i++){
dp[i][0]=0;
}
for(int i=0;i<=m;i++){
dp[0][i]=0;
}
for(int i=1;i<=n;i++){
dp[i][1]=i;
}
for(int j=2;j<=m;j++){
for(int i=1;i<=n;i++){
for(int k=2;k<=i;k++)
dp[i][j]=min(dp[i][j],max(dp[k-1][j-1],dp[i-k][j])+1);
}
}
printf("%d\n",dp[n][m]);
return 0;
}
举一反三,运气最好情况下最优策略,即每次挑中都是最好的楼层,测试次数最少,所有最少次数里最少次数的那个 dp[i][j]=min(dp[i][j],min(dp[i-k][j]+1,dp[k-1][j-1]+1)+1);
运气最差情况下的最差策略,所有最多测试次数里测试次数最多的 dp[i][j]=max(dp[i][j],max(dp[i-k][j]+1,dp[k-1][j-1]+1)+1);
运气最好,最差策略,所有最少次数里最多次那个dp[i][j]=max(dp[i][j],min(dp[i-k][j]+1,dp[k-1][j-1]+1)+1);