抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

粉刷房子 III

在一个小城市里,有 m 个房子排成一排,你需要给每个房子涂上 n 种颜色之一(颜色编号为 1n )。有的房子去年夏天已经涂过颜色了,所以这些房子不需要被重新涂色。

我们将连续相同颜色尽可能多的房子称为一个街区。(比方说 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 。

 

示例 1:

输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
输出:9
解释:房子涂色方案为 [1,2,2,1,1]
此方案包含 target = 3 个街区,分别是 [{1}, {2,2}, {1,1}]。
涂色的总花费为 (1 + 1 + 1 + 1 + 5) = 9。

示例 2:

输入:houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
输出:11
解释:有的房子已经被涂色了,在此基础上涂色方案为 [2,2,1,2,2]
此方案包含 target = 3 个街区,分别是 [{2,2}, {1}, {2,2}]。
给第一个和最后一个房子涂色的花费为 (10 + 1) = 11。

示例 3:

输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[1,10],[10,1],[1,10]], m = 5, n = 2, target = 5
输出:5

示例 4:

输入:houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3
输出:-1
解释:房子已经被涂色并组成了 4 个街区,分别是 [{3},{1},{2},{3}] ,无法形成 target = 3 个街区。

 

提示:

  • m == houses.length == cost.length
  • n == cost[i].length
  • 1 <= m <= 100
  • 1 <= n <= 20
  • 1 <= target <= m
  • 0 <= houses[i] <= n
  • 1 <= cost[i][j] <= 10^4
Related Topics
  • 动态规划
  • 分析

    • 将房区初始颜色编码从0开始计算,-1表示未涂颜色。
    • dp[i][j][k]为第i个房子涂成颜色j的花费,它属于第k个街区
    • 我们讨论第i个房子花费:若i!=0,设第i-1个房子颜色为j0
      • 对于houses[i] = -1,即房子未涂颜色。分为两种情况:
        • j = j0:颜色和i-1一致,ii-1属于同一街区,得如下转移方程:
          $$
          dp[i][j][k] = dp[i-1][j][k] + const[i][j]
          $$
        • j != j0:颜色变化,ii-1不属于同一街区,得如下转移方程:
          $$
          dp[i][j][k] = dp[i-1][j0][k-1] + const[i][j]
          $$
      • 对于houses[i] != -1,即房子有初始颜色j,这种情况必须将房子涂成颜色j。同样分为两种情况:
        • j = j0:颜色和i-1一致,ii-1属于同一街区,这时不需要额外为i涂色。得如下转移方程:
          $$
          dp[i][j][k] = dp[i-1][j][k]
          $$
        • j != j0:颜色变化,ii-1不属于同一街区,这时不需要额外为i涂色,得如下转移方程:
          $$
          dp[i][j][k] = dp[i-1][j0][k-1]
          $$
    • i = 0,由于第一个房子,所以k = 0,花费不由上一个房子转移得到。,分为两种情况:
      • houses[i] = -1,即房子未涂颜色,花费:const[i][j]
      • houses[i] != -1,即房子有初始颜色j,j = j0,花费:0

    转化为代码:

    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    public class Solution1473 {

    private static final int INFTY = Integer.MAX_VALUE / 2;

    public int minCost(int[] houses, int[][] cost, int m, int n, int target) {
    for (int i = 0; i < houses.length; i++) {
    houses[i]--;
    }

    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 i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
    if (houses[i] != -1 && houses[i] != j) {
    continue;
    }
    for (int k = 0; k < target; k++) {
    for (int j0 = 0; j0 < n; j0++) {
    if (j == j0) {
    if (i == 0) {
    if (k == 0) {
    // 第一个房子初始为0
    dp[i][j][k] = 0;
    }
    } else {
    dp[i][j][k] = Math.min(dp[i][j][k], dp[i - 1][j][k]);
    }
    } else if (i > 0 && k > 0) {
    // 非第一个房子
    dp[i][j][k] = Math.min(dp[i][j][k], dp[i - 1][j0][k - 1]);
    }

    }
    if (houses[i] == -1) {
    // 第一个房子或者变更房区--未涂颜色
    dp[i][j][k] += cost[i][j];
    }
    }
    }
    }
    int ans = INFTY;
    for (int i = 0; i < n; i++) {
    ans = Math.min(ans, dp[m - 1][i][target - 1]);
    }
    return ans == INFTY ? -1 : ans;
    }
    }

    评论