1473. 粉刷房子 III
在一个小城市里,有 m 个房子排成一排,你需要给每个房子涂上 n 种颜色之一(颜色编号为 1 到 n )。有的房子去年夏天已经涂过颜色了,所以这些房子不可以被重新涂色。
我们将连续相同颜色尽可能多的房子称为一个街区。(比方说 houses = [1,2,2,3,3,2,1,1] ,它包含 5 个街区 [{1}, {2,2}, {3,3}, {2}, {1,1}] 。)
给你一个数组 houses ,一个 m * n 的矩阵 cost 和一个整数 target ,其中:
houses[i]:是第 i 个房子的颜色,0 表示这个房子还没有被涂色。
cost[i][j]:是将第 i 个房子涂成颜色 j+1 的花费。
请你返回房子涂色方案的最小总花费,使得每个房子都被涂色后,恰好组成 target 个街区。如果没有可用的涂色方案,请返回 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/paint-house-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
动态规划
import java.util.Arrays;
class Solution {
// 极大值
// 选择 Integer.MAX_VALUE / 2 的原因是防止整数相加溢出
static final int INFTY = Integer.MAX_VALUE / 2;
public int minCost(int[] houses, int[][] cost, int m, int n, int target) {
// 将颜色调整为从 0 开始编号,没有被涂色标记为 -1
for (int i = 0; i < m; ++i) {
--houses[i];
}
// dp 所有元素初始化为极大值
int[][][] dp = new int[m][n][target];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
Arrays.fill(dp[i][j], INFTY);
}
}
for (int house = 0; house < m; ++house) {
for (int color = 0; color < n; ++color) {
if (houses[house] == -1 || houses[house] == color) {
for (int region = 0; region < Math.min(target, house + 1); ++region) {
/**
* 枚举前一个房子
*/
for (int preColor = 0; preColor < n; ++preColor) {
/**
* 当前房子与前一个房子颜色相同
*/
if (color == preColor) {
if (house == 0) {
if (region == 0) {
dp[house][color][region] = 0;
}
} else {
dp[house][color][region] = Math.min(dp[house][color][region], dp[house - 1][color][region]);
}
} else if (house > 0 && region > 0) {
dp[house][color][region] = Math.min(dp[house][color][region], dp[house - 1][preColor][region - 1]);
}
}
if (dp[house][color][region] != INFTY && houses[house] == -1) {
dp[house][color][region] += cost[house][color];
}
}
}
}
}
int ans = INFTY;
for (int j = 0; j < n; ++j) {
ans = Math.min(ans, dp[m - 1][j][target - 1]);
}
return ans == INFTY ? -1 : ans;
}
}
动态规划(优化)
import java.util.Arrays;
class Solution {
// 极大值
// 选择 Integer.MAX_VALUE / 2 的原因是防止整数相加溢出
static final int INFTY = Integer.MAX_VALUE / 2;
public int minCost(int[] houses, int[][] cost, int m, int n, int target) {
// 将颜色调整为从 0 开始编号,没有被涂色标记为 -1
for (int i = 0; i < m; ++i) {
--houses[i];
}
// dp 所有元素初始化为极大值
int[][][] dp = new int[m][n][target];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
Arrays.fill(dp[i][j], INFTY);
}
}
int[][][] best = new int[m][target][3];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < target; ++j) {
best[i][j][0] = best[i][j][2] = INFTY;
best[i][j][1] = -1;
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (houses[i] == -1 || houses[i] == j) {
for (int k = 0; k < target; ++k) {
if (i == 0) {
if (k == 0) {
dp[i][j][k] = 0;
}
} else {
dp[i][j][k] = dp[i - 1][j][k];
if (k > 0) {
// 使用 best(i-1,k-1) 直接得到 dp(i,j,k) 的值
int first = best[i - 1][k - 1][0];
int firstIdx = best[i - 1][k - 1][1];
int second = best[i - 1][k - 1][2];
dp[i][j][k] = Math.min(dp[i][j][k], (j == firstIdx ? second : first));
}
}
if (dp[i][j][k] != INFTY && houses[i] == -1) {
dp[i][j][k] += cost[i][j];
}
int first = best[i][k][0];
int second = best[i][k][2];
if (dp[i][j][k] < first) {
best[i][k][2] = first;
best[i][k][0] = dp[i][j][k];
best[i][k][1] = j;
} else if (dp[i][j][k] < second) {
best[i][k][2] = dp[i][j][k];
}
}
}
}
}
int ans = INFTY;
for (int j = 0; j < n; ++j) {
ans = Math.min(ans, dp[m - 1][j][target - 1]);
}
return ans == INFTY ? -1 : ans;
}
}
心之所向,素履以往 生如逆旅,一苇以航

浙公网安备 33010602011771号