题目描述
简单来说,就是初始有 m 个机器,w 个工人,每天可以生产 m × w 个蛋糕。生产的蛋糕又可以拿去购买额外的机器或雇佣工人,机器和工人的成本都是 p 个蛋糕。
现在要求,生产 n 个蛋糕最少要多少天。
算法描述
从贪心的角度,要达到最大产能,应该在生产的初期就持续增加机器和工人数。因此,机器和工人数在生产过程中应该是一个持续上后,后续保持不变的一个过程,这样才可能花费最少的天数生产 n 个蛋糕。
故可以得出如下的贪心求解过程:
- 先计算截至今天生产的蛋糕总数
sum是否超过n,若超过,贪心求解过程结束。 - 若
sum不超过n,则将蛋糕尽可能多的购置机器或雇佣工人,增加m × w的值 - 假设从今天开始,不再继续增加机器数和工人数,即每天最多生产
m × w个蛋糕,计算总共需要花费多少天,更新最少天数res - 下一天的计算继续从步骤 1 开始
接下来,我们讨论机器数和工人数如何增加。
由于每天可以生产的蛋糕数是机器数和工人数的乘积,按照不等式的特性,假定 m + w 固定,要让 m × w 尽可能的大,应该让 m 和 w 之间尽可能接近。因此,我们得出购买额外的机器或雇佣工人的基本规则:若 m 大了则增加 w,若 w 大了则增加 m,直至二者尽可能相等。
贪心完整代码
public class Main {
public static int solution(int m, int w, int p, int n) {
// Please write your code here
int res = n / (m * w + 1) + 1;
int days = res;
int sum = 0;
for(int i = 1; i <= days; i++) {
sum += m * w;
if (sum >= n) {
res = Math.min(res, i);
break;
}
while( sum >= p ) {
if (m < w) {
m++;
} else {
w++;
}
sum -= p;
}
res = Math.min(res, i + (n - sum) / (m * w + 1) + 1);
}
System.out.println(res);
return res;
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution(3, 1, 2, 12) == 3);
System.out.println(solution(10, 5, 30, 500) == 8);
System.out.println(solution(3, 5, 30, 320) == 14);
}
}
另一种思路:二分 + 贪心
虽然纯贪心的思路已经可以通过本题,但还有一种思路就是二分 + 贪心。
如果 m 和 w 的数量始终不变,我们可以得出最大所需天数为 n / (m + w + 1) + 1
也就是说,我们最少生产天数一定在 [1, n / (m + w + 1) + 1] 这个区间内
知道了这个区间,我们就可以使用二分查找缩短搜索区间,判断能否在给定时间 days 内完成 n 个蛋糕的生产。而判断过程则是利用上述的贪心策略。不同的是,如果在判断过程,发现当前生产的蛋糕数 sum 加上剩余天数 days - day 每天生产 m × w 的蛋糕数超过了 n,判断就可以提前终止,缩短搜索区间,继续查找最少天数。
这种方法的好处很明显,可以减小我们一开始的搜索区间,但坏处也很明显,贪心过程存在重复计算(但其实可以用额外变量存储中间状态的计算结果)