题目难度:二星
考察点:二分查找
方法1:暴力
1.分析:
这个题目的题意有点乱,我们仔细梳理一下,其实就有n堆猫粮,小猫需要吃H小时,它每小时最多吃K粒,如果某一堆在一小时内没有吃完,那么下一个小时就继续吃;如果某一堆在一小时之内不够吃,它也不能吃别的了,然后输出一个在H小时之内吃完全部猫粮的最小的K 。其实这个题我们考虑一种暴力的情况,直接将K从1开始枚举m,如果某个K满足条件(K小时之内吃完全部猫粮),那么此时的K一定就是最小的,我们输出就可以了。我们该如何计算某个K是不是符合条件呢?其实可以这样做,假设有n堆猫粮,第i堆猫粮有a[i]粒,那么就可以遍历所有猫粮,对于第i堆猫粮计算需要吃的小时数,计算方法为如果a[i]%K==0,那么结果等于a[i]/k,否则结果等于a[i]/k+1,那么我们将这n堆猫粮所耗费的时间计算出来,假设为ans,判断ans是否小于等于H,如果满足条件,那么此时的K就是符合条件的输出即可。
(1). 需要处理一下输入,得到数组a和H。
(2). 写一个判断当前k是否满足条件的函数,实现方法就如上面所述。
(3).开始while(1),K从1开始进行枚举,如果满足条件,就break。
(4). 输出第一个满足条件的K。
2.复杂度分析:
时间复杂度:O(max(a[i]))空间复杂度:O(n)
3.代码:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6+5; int a[MAXN]; int n = 0, H; bool check(int x) { int ans = 0; for(int i=0; i<n; i++) ans += (a[i]%x)?a[i]/x+1:a[i]/x; return ans <= H; } int main() { while(cin>>a[n++]); n--; H = a[n-1]; n--; int ans = 1; while(1) { if(check(ans)) { cout<<ans<<endl; break; } ans++; } return 0; }
方法2:二分
1.分析:
由于这个题的数据比较水,所以上面的方法也是可以通过的,但是显然上面的方法不是最优的,那么我们来考虑一个更优的算法,只要是查找就少不了考虑二分,所以接下来我就用二分的思想来解这道题,如果想用二分的话,首先来确定一下二分的范围,即最大值和最小值,显然最大值就是max(a[i]),那么最小值是什么呢? 从理论上来说,最小值就是sum(a[i])/H(这是理论值),所以我们就在这两个范围内二分这个进食速度就可以了,其实就是求一个lower_bound,因为判断条件已经在方法1中描述完毕了,剩下的就是枚举中间值,二分就可以了。
(1). 还是需要处理一下输入,得到数组a和H;
(2). 写一个判断当前k是否满足条件的函数,实现方法就如上面方法1中所述;
(3). 进行二分,最小值为sum / H, 最大值为max(a[i]);
空间复杂度:O(n)
(4). 输出二分之后的结果。
2.复杂度分析:
时间复杂度:O(nlog(n))空间复杂度:O(n)
3.代码:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6+5; int a[MAXN]; int n = 0, H; bool check(int x) { int ans = 0; for(int i=0; i<n; i++) ans += (a[i]%x)?a[i]/x+1:a[i]/x; return ans <= H; } int main() { while(cin>>a[n++]); n--; H = a[n-1]; n--; int l = 1, r = 1, sum = 0; for(int i=0; i<n; i++) { r = max(r, a[i]); sum += a[i]; } l = sum / H; while(l <= r) { int m = (l + r) >> 1; if(check(m)){ if(!check(m-1)) { l = m; break; } r = m-1; } else l = m + 1; } cout<<l<<endl; return 0; }