LeetCode破解之房子装修

224 阅读3分钟

「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

在一个小城市里,有 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 。

示例 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。

思路

这题好难,看了好久提示,才想到变化的哪几个状态。

  • index:下标,表示第几个屋子,从0开始计数
  • color:颜色,从0开始计数,和cost对应
  • neighborhoods:前index个屋子连续颜色的组数

然后对三个状态进行规划,总结状态方程。

dp[i][j][k] 表示 [0,i]都已经涂上颜色了,第 i 个房子的颜色是 j,它属于第 k 个街区 的最小值。

对于houses[i - 1] 已经上色的(houses[i - 1] != 0), 则只会有dp[i][j][houses[i - 1]]存在dp[i][j][houses[i - 1]]的最小值为 前 i - 1个房子被分成j个社区,且第 i - 1号房子颜色为houses[i - 1] 或者 前 i - 1个房子被分成 j - 1个社区且第i - 1号房子颜色不为houses[i - 1]

class Solution {
    public int minCost(int[] houses, int[][] cost, int m, int n, int target) {
        int[][][] dp = new int[m+1][m+1][n+1];//index blocks nowcolor
        for (int[][] ints : dp) {
            for (int[] anInt : ints) {
                Arrays.fill(anInt,99999999);
            }
        }
        for (int i = 0; i < n+1; i++) {
           dp[0][0][i]=0;
        }
        for (int i = 1; i < m+1 ; i++) {
            for (int j = 1; j <= i ; j++) {
                for (int k = 1; k < n+1 ; k++) {
                    if (houses[i-1]==0) {
                        for (int l = 1; l < n+1 ; l++) {
                            if (l!=k)
                                dp[i][j][k]=Math.min(dp[i-1][j-1][l]+cost[i-1][k-1],Math.min(dp[i-1][j][k]+cost[i-1][k-1],dp[i][j][k]));
                        }
                    }else {
                        if (k==houses[i-1])
                            dp[i][j][houses[i-1]] = Math.min(dp[i-1][j][houses[i-1]],dp[i][j][houses[i-1]]);
                        else
                            dp[i][j][houses[i-1]] = Math.min(dp[i-1][j-1][k],dp[i][j][houses[i-1]]);
                    }
                }
            }
        }
        int min =9999999;
        for (int i = 0; i <n+1 ; i++) {
            min=Math.min(dp[m][target][i],min);
        }
        return min==9999999?-1:min;
    }
}