题目
Leetcode链接
给你两个长度为 n 下标从 0 开始的整数数组 cost 和 time ,分别表示给 n 堵不同的墙刷油漆需要的开销和时间。你有两名油漆匠:
- 一位需要 付费 的油漆匠,刷第
i堵墙需要花费time[i]单位的时间,开销为cost[i]单位的钱。 - 一位 免费 的油漆匠,刷 任意 一堵墙的时间为
1单位,开销为0。但是必须在付费油漆匠 工作 时,免费油漆匠才会工作。
请你返回刷完 n 堵墙最少开销为多少。
示例1:
- 输入: cost = [1,2,3,2], time = [1,2,3,2]
- 输出:3
示例2:
- 输入:cost = [2,3,4,2], time = [1,1,1,1]
- 输出:4
提示:
1 <= cost.length <= 500cost.length == time.length1 <= cost[i] <= 1061 <= time[i] <= 500
题解
分析:免费油漆匠的工作效率更高,但是免费的油漆匠是根据收费油漆匠的工作时间决定的。因此一个收费油漆匠能刷 time[i](免费油漆匠刷的墙) + 1(收费油漆匠刷的墙),因此可以将问题看成一个 0-1 背包问题。
0-1 背包模板:
int n; // 物品个数
int c; // 背包容量
int[] v; // v[i] 表示第 i 个物品的价值
int[] w; // w[i] 表示第 i 个物品的重量
int[] dp = new int[c + 1];
// 初始化
dp[x] = ...
// 状态转移
for (int i = 1; i <= n; i++) {
for (int j = c; j >= w[i - 1] ; j--) {
dp[j] = Math.max(dp[j], dp[j - w[i - 1]] + v[i - 1]);
}
}
return dp[c];
当前问题:要求最小花费,cost 对应 v,需要将 Math.max 变成 Math.min,重量对应 time。
代码:
class Solution {
public int paintWalls(int[] cost, int[] time) {
int len = cost.length;
int[] dp = new int[len+1];
Arrays.fill(dp, Integer.MAX_VALUE/5);
dp[0] = 0;
for (int i = 0; i < len; i++) {
for (int j = len; j > 0; j--) {
// 在选或不选油漆匠之间选择花费小的一个
dp[j] = Math.min(dp[j], dp[Math.max(j - time[i] - 1, 0)] + cost[i]);
}
}
return dp[len];
}
}