LeetCode每日一题——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 。

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

难度:困难

 

解题思路

特殊处理第一个房子,然后前2栋房子到前mm栋房子用dp,一开始都需要初始化为无穷大,后面计算的时候需要利用这个来判断是否要更新值。注意点:一开始我以为i == 0 || j == 0 || k == 0三种0的情况不需要初始化为无穷大,后面发现自己错了,因为这种情况是永远达不到的,所以当我们当前所计算的问题要用到这个子问题时,就不能用其去更新,因为这种子问题方案自己本身就不行,不能用作计算原问题的解

 

AC代码

 1 class Solution {
 2     public int minCost(int[] houses, int[][] cost, int m, int n, int target) {
 3         int[][][] f = new int[m + 1][n + 1][target + 1];
 4 
 5         for (int i = 0; i <= m; i++) {
 6             for (int j = 0; j <= n; j++) {
 7                 for (int k = 0; k <= target; k++) {
 8                     if (i == 0 || j == 0 || k == 0) {
 9                         // 初始化为无穷大
10                         f[i][j][k] = Integer.MAX_VALUE;
11                         continue;
12                     }
13 
14                     f[i][j][k] = Integer.MAX_VALUE;
15 
16                     // 注意:这里一定要特判i == 1,只有一栋房子的时候可以简单直接的求解
17                     if (i == 1) {
18                         // 判断这个房子是否已涂过颜色
19                         // 这里我们只考虑组成1个街区,其他街区的都不可能组成,即为无穷大
20                         if (houses[0] != 0) {
21                             f[1][houses[0]][1] = 0; 
22                         } else {
23                             for (int a = 1; a <= n; a++) {
24                                 f[1][a][1] = cost[0][a - 1];
25                             }
26                         }
27                         continue;
28                     }
29 
30                     // 2-m
31                     if (houses[i - 1] != 0) {
32                         if (j != houses[i - 1]) {
33                             continue;
34                         }
35                         // 讨论1-n种颜色
36                         for (int a = 1; a <= n; a++) {
37                             if (a == j) {
38                                 if (f[i - 1][a][k] == Integer.MAX_VALUE) {
39                                     continue;
40                                 }
41                                 f[i][j][k] = Math.min(f[i][j][k], f[i - 1][a][k]);
42                             } else {
43                                 if (f[i - 1][a][k - 1] == Integer.MAX_VALUE) {
44                                     continue;
45                                 }
46                                 f[i][j][k] = Math.min(f[i][j][k], f[i - 1][a][k - 1]);
47                             }
48                         }
49                     } else {
50                         // 讨论1-n种颜色
51                         for (int a = 1; a <= n; a++) {
52                             if (a == j) {
53                                 if (f[i - 1][a][k] == Integer.MAX_VALUE) {
54                                     continue;
55                                 }
56                                 f[i][j][k] = Math.min(f[i][j][k], f[i - 1][a][k] + cost[i - 1][j - 1]);
57                             } else {
58                                 if (f[i - 1][a][k - 1] == Integer.MAX_VALUE) {
59                                     continue;
60                                 }
61                                 f[i][j][k] = Math.min(f[i][j][k], f[i - 1][a][k - 1] + cost[i - 1][j - 1]);
62                             }
63                         }
64                     }
65                 }
66             }
67         }
68 
69         // 选最小
70         int ans = Integer.MAX_VALUE;
71         for (int i = 1; i <= n; i++) {
72             ans = Math.min(ans, f[m][i][target]);
73         }
74 
75         return ans >= Integer.MAX_VALUE ? -1 : ans;
76     }
77 }

leetcode链接

相似题目

LintCode上的房屋染色

posted @ 2021-05-05 23:34  没有你哪有我  阅读(190)  评论(0编辑  收藏  举报