poj3783 Balls
题意:
有一些鸡蛋,我们现在想知道这些鸡蛋的硬度。然后现在有一座很高很高的大楼里,我们现在要在这座大楼上测试鸡蛋的硬度。每个鸡蛋的硬度相同,鸡蛋的硬度定义为:如果鸡蛋从第 m 层上掉下来没有破裂,而从第 m+1 层上掉下来就破裂了,那么这个鸡蛋的硬度就是 m 。某个鸡蛋如果在实验中破裂了就永远的损失了。我们现在有 n 个鸡蛋。那么在最坏情况下我们最少需要做多少次实验呢?
思路:
这是一个很经典的dp问题,设dp[n,m]是第i层楼,有k个鸡蛋时找到符合条件的最少测试次数
则一个鸡蛋从第 i 层扔下,如果碎了,还剩 m−1 个鸡蛋,为确定下面楼层中的安全位置,还需要dp[i−1,m−1] 次(子问题);不碎的话,上面还有 n−i 层,还需要 dp[n−i,m]次(子问题,实体 n 层楼的上 n−i 层需要的最少判断次数和实体 n−i 层楼需要的最少判断次数其实是一样的)
这里因为是要找最坏情况的最优解
所以在遍历每层楼的时候,应该要选择每一层楼中两种情况的最大值,然后再去比较其中的最小值
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#define __int128 LL
using namespace std;
typedef long long ll;
const int mod = 1e9;
const int maxn = 1e3 + 5;
const int INF = 1e9 + 7;
int dp[maxn][60];//dp[i][j]:表示在 i 层楼 还有 j 个鸡蛋的最小判断次数
void DP(int n,int m)
{
memset(dp,0,sizeof dp);
//对于一个鸡蛋,只能一层一层的试
for(int i = 1; i <= n; i++){
dp[i][1] = i;
}
//对于只有一层,肯定有且仅有一次
for(int i = 1; i <=m; i++){
dp[1][i] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 2; j <= m; j++){
dp[i][j] = i;//初始最坏结果是i次
for(int k = 1; k <= i; k++) dp[i][j] = min(dp[i][j] ,max(dp[k - 1][j - 1] + 1,dp[i - k][j] + 1));
}
}
}
int main()
{
int t;
cin>>t;
while(t--){
int op,n,m;
cin>>op>>m>>n;
DP(n,m);
cout<<op<<' '<<dp[n][m]<<endl;
}
return 0;
}```