x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。 各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。 x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。 如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。 特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。 如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n 为了减少测试次数,从每个厂家抽样3部手机参加测试。 某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢? 请填写这个最多测试次数 注意:需要填写的是一个整数,不要填写任何多余内容
这题有两种解题思路:
1.数学逻辑推导
看懂后就是手算了:https://www.cnblogs.com/wizarderror/p/10548253.html
2.动态规划
看到这四个字首先是头皮发麻,快一个星期不写了,当时学的那会被动规弄的死去或来的
定义状态dp[ind][cnt]:ind层楼,cnt部手机时最坏运气下最少的测试次数
状态转移方程:dp[ind][cnt] = Min( 1 + dp[ind-1][cnt] , 1 + Max( dp[k-1][cnt-1] , dp[ind-k][cnt] ) (1 < k < ind)
注意ind=1、2的时候,k是不存在的,这时候采用最大值 dp[ind-1][cnt]+1 即可,初始化 dp[0][cnt]=0
代码:
#include <bits/stdc++.h> using namespace std; int dp[1005][50]; int main() { int n,m; scanf("%d%d",&n,&m); memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; i++)//边界初始化 dp[i][1]=i; for (int cnt = 2; cnt<= m; cnt++) { for (int ind = 1; ind <= n; ind++) { dp[ind][cnt] = 1+dp[ind-1][cnt];//最坏的情况 for (int k = 2; k < ind; k++) dp[ind][cnt] = min(dp[ind][cnt],1+max(dp[k-1][cnt-1],dp[ind-k][cnt])); } } printf("%d ",dp[n][m]); return 0; }
以下内容帮助理解:
从k=2扔到k=ind-1的这个过程是为了检查在这些楼层扔一部手机是否能根据历史数据得到更优的结果; (我们已经计算过手机 cnt-1 部的所有情况和手机 cnt 部楼层数低于当前层数的所有数据) 最坏情况(也就是最大值)必然是确定ind-1层所用手机数+1; 先求得最大值后,再设定k在 2~ind-1 之间查找是否存在可能的最小值; 尝试在 2~ind-1 楼层扔手机会将产生两种可能,一种是手机破碎,那么还需要确定的就是手机少一部(cnt-1)确定 k-1 层数; 另一种自然是手机完好,那么还需要用 cnt 部手机确定 ind-k 层数,这两种情况所需的历史值我们都已经计算过了! 这体现的是不断通过选择最优分块的思路,一层一层确定~~
参考自:https://blog.csdn.net/belous_zxy/article/details/80543276