测试次数 / 耐摔指数
题目提交点
题目思路讲解
- 先从数据入手,简单的模拟一下
以第三层,三个手机为例:
从第一层开始摔:
如果该层手机完好,那么按照运气不好的情况,后面两层也是手机完好,一共三次。
如果该层手机摔坏,直接测出来,一共一次。
所以从第一层开始摔,最多测试三次。
从第二层开始摔:
如果该层手机完好,那么按照运气不好的情况,后面一层好或不好,一共都是两次。
如果该层手机摔坏,那么按照运气不好的情况,前面一层好或不好,一共也都是两次。
所以从第二层开始摔,最多测试两次。
从第三层开始摔:
如果该层手机完好,直接出答案,一共一次。
如果该层手机摔坏,最坏情况下,下面两层都把手机摔坏了,手机损失3个,一共三次。
所以从第三层开始摔,最多测试三次。
然后一总结得出最多结果为两次。
- 总结,发现规律
手机的测试次数受到手机个数和层数的影响,每一次比对都没有固定的规律,不知道哪一种策略是最好的,有点偏向于动态规划,所以尝试着使用DP的思想去做这个题目。
- 分析DP
- 发现最优子结构性质
以好坏进行进行划分,将其化为两个部分进行比较,将手机向下摔,如果是好的,那么就往上面走,如果是坏的,那么就我往下面走,对两边取大的那一方。
- 画 y a n 氏 D P 图 yan氏DP图 yan氏DP图
集合表示:剩余i层j台手机最坏情况下的测试次数。(往上走摔手机和往下走摔手机是相互独立的,没有互相干扰,而且具有重叠子问题性质,所以使用关键字”剩余“来表示集合)。
属性:每一次都是采用最佳策略,所以是取最小值。
状态划分:以从哪一层开始摔,摔的好坏作为划分依据。
- 数据初始化
只有一台手机的话,最坏情况下是从第一层开始摔,直到楼顶,还是好的,所以要初始化一台手机的情况。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << endl;
#define mod(x) (x) % MOD
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 10000 + 10;
int f[N][4];
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false); // 取消cin与stdin 的同步
cout.tie(0), cin.tie(0);
int m = 3, n;
cin >> n;
_rep(i, 1, n) f[i][1] = i;
_rep(i, 1, n) _rep(j, 2, m) {
f[i][j] = 0x3f3f3f3f;
_rep(k, 1, i)
f[i][j] = min(f[i][j], max(f[k - 1][j - 1], f[i - k][j]) + 1);
}
cout << f[n][m] << endl;
return 0;
}