粉刷房子(dp)

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

这个题就是在有限集合中选取最优解,就是一个dp

dp[i][j][k]代表的是前i个房子已经染色了j个并且第i个房子为k这个颜色的最小值

class Solution {
public:
//f[i][j][k]代表的是前i个房子已经涂色了j个,并且第i个为颜色K的最小值
    int minCost(vector<int>& hs, vector<vector<int>>& cost, int m, int n, int target) {
        const int INF = 1e8;
        vector<vector<vector<int>>> f(m, vector<vector<int>>(target + 1, vector<int>(n + 1, INF)));
        if(hs[0]){
            f[0][1][hs[0]]=0;
        }
        else{
            for(int i=1;i<=n;i++){
                f[0][1][i]=cost[0][i-1];
            }
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<=target;j++){
                if(hs[i]){//这个房子已经涂了颜色
                    int k=hs[i];
                    for(int u=1;u<=n;u++){
                        if(u==k){
                            f[i][j][k]=min(f[i][j][k],f[i-1][j][u]);
                        }
                        else{
                            f[i][j][k]=min(f[i][j][k],f[i-1][j-1][u]);
                        }
                    }
                }
                else{//这个房子没有涂颜色
                    for(int k=1;k<=n;k++){
                        for(int u=1;u<=n;u++){
                            if (u == k)//枚举上一个房子和则一个房子
                                f[i][j][k] = min(f[i][j][k], f[i - 1][j][u] + cost[i][k - 1]);
                            else
                                f[i][j][k] = min(f[i][j][k], f[i - 1][j - 1][u] + cost[i][k - 1]);
                        }
                    }
                }
            }
        }
        int res = INF;
        for (int i = 1; i <= n; i ++ ) res = min(res, f[m - 1][target][i]);
        if (res == INF) res = -1;
        return res;
    }
};

 

posted @ 2021-05-08 00:35  lipu123  阅读(83)  评论(0)    收藏  举报