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;
    }
}
posted @ 2022-01-20 16:19  Tianyiya  阅读(37)  评论(0)    收藏  举报