题目描述
假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有 n
种不同类型的金属可以使用,并且你可以使用 k
台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。
对于第 i
台机器而言,创建合金需要 composition[i][j]
份 j
类型金属。最初,你拥有 stock[i]
份 i
类型金属,而每购入一份 i
类型金属需要花费 cost[i]
的金钱。
给你整数 n
、k
、budget
,下标从 1 开始的二维数组 composition
,两个下标从 1 开始的数组 stock
和 cost
,请你在预算不超过 budget
金钱的前提下,最大化 公司制造合金的数量。
所有合金都需要由同一台机器制造。
返回公司可以制造的最大合金数。
示例 1:
输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,0], cost = [1,2,3]
输出:2
解释:最优的方法是使用第 1 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 2 份第 1 类金属。
- 2 份第 2 类金属。
- 2 份第 3 类金属。
总共需要 2 * 1 + 2 * 2 + 2 * 3 = 12 的金钱,小于等于预算 15 。
注意,我们最开始时候没有任何一类金属,所以必须买齐所有需要的金属。
可以证明在示例条件下最多可以制造 2 份合金。
示例 2:
输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,100], cost = [1,2,3]
输出:5
解释:最优的方法是使用第 2 台机器来制造合金。
要想制造 5 份合金,我们需要购买:
- 5 份第 1 类金属。
- 5 份第 2 类金属。
- 0 份第 3 类金属。
总共需要 5 * 1 + 5 * 2 + 0 * 3 = 15 的金钱,小于等于预算 15 。
可以证明在示例条件下最多可以制造 5 份合金。
示例 3:
输入:n = 2, k = 3, budget = 10, composition = [[2,1],[1,2],[1,1]], stock = [1,1], cost = [5,5]
输出:2
解释:最优的方法是使用第 3 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 1 份第 1 类金属。
- 1 份第 2 类金属。
总共需要 1 * 5 + 1 * 5 = 10 的金钱,小于等于预算 10 。
可以证明在示例条件下最多可以制造 2 份合金。
提示:
1 <= n, k <= 100
0 <= budget <= 108
composition.length == k
composition[i].length == n
1 <= composition[i][j] <= 100
stock.length == cost.length == n
0 <= stock[i] <= 108
1 <= cost[i] <= 100
解法
方法一:二分查找
我们注意到,所有合金都需要由同一台机器制造,因此我们可以枚举使用哪一台机器来制造合金。
对于每一台机器,我们可以使用二分查找的方法找出最大的整数 $x$,使得我们可以使用这台机器制造 $x$ 份合金。找出所有 $x$ 中的最大值即为答案。
时间复杂度 $O(n \times k \times \log M)$,其中 $M$ 是二分查找的上界,本题中 $M \leq 2 \times 10^8$。空间复杂度 $O(1)$。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | class Solution:
def maxNumberOfAlloys(
self,
n: int,
k: int,
budget: int,
composition: List[List[int]],
stock: List[int],
cost: List[int],
) -> int:
ans = 0
for c in composition:
l, r = 0, budget + stock[0]
while l < r:
mid = (l + r + 1) >> 1
s = sum(max(0, mid * x - y) * z for x, y, z in zip(c, stock, cost))
if s <= budget:
l = mid
else:
r = mid - 1
ans = max(ans, l)
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | class Solution {
int n;
int budget;
List<List<Integer>> composition;
List<Integer> stock;
List<Integer> cost;
boolean isValid(long target) {
for (List<Integer> currMachine : composition) {
long remain = budget;
for (int j = 0; j < n && remain >= 0; j++) {
long need = Math.max(0, currMachine.get(j) * target - stock.get(j));
remain -= need * cost.get(j);
}
if (remain >= 0) {
return true;
}
}
return false;
}
public int maxNumberOfAlloys(int n, int k, int budget, List<List<Integer>> composition,
List<Integer> stock, List<Integer> cost) {
this.n = n;
this.budget = budget;
this.composition = composition;
this.stock = stock;
this.cost = cost;
int l = -1;
int r = budget / cost.get(0) + stock.get(0);
while (l < r) {
int mid = (l + r + 1) >> 1;
if (isValid(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | class Solution {
public:
int maxNumberOfAlloys(int n, int k, int budget, vector<vector<int>>& composition, vector<int>& stock, vector<int>& cost) {
auto isValid = [&](long long target) {
for (int i = 0; i < k; i++) {
long long remain = budget;
auto currMachine = composition[i];
for (int j = 0; j < n && remain >= 0; j++) {
long long need = max(0LL, target * currMachine[j] - stock[j]);
remain -= need * cost[j];
}
if (remain >= 0) {
return true;
}
}
return false;
};
long long l = 0, r = budget + stock[0];
while (l < r) {
long long mid = (l + r + 1) >> 1;
if (isValid(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | func maxNumberOfAlloys(n int, k int, budget int, composition [][]int, stock []int, cost []int) int {
isValid := func(target int) bool {
for _, currMachine := range composition {
remain := budget
for i, x := range currMachine {
need := max(0, x*target-stock[i])
remain -= need * cost[i]
}
if remain >= 0 {
return true
}
}
return false
}
l, r := 0, budget+stock[0]
for l < r {
mid := (l + r + 1) >> 1
if isValid(mid) {
l = mid
} else {
r = mid - 1
}
}
return l
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | function maxNumberOfAlloys(
n: number,
k: number,
budget: number,
composition: number[][],
stock: number[],
cost: number[],
): number {
let l = 0;
let r = budget + stock[0];
const isValid = (target: number): boolean => {
for (const currMachine of composition) {
let remain = budget;
for (let i = 0; i < n; ++i) {
let need = Math.max(0, target * currMachine[i] - stock[i]);
remain -= need * cost[i];
}
if (remain >= 0) {
return true;
}
}
return false;
};
while (l < r) {
const mid = (l + r + 1) >> 1;
if (isValid(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
|