阿里云 超级码力在线编程大赛初赛 第3场 题目2. 房屋染色(DP)

文章目录

1. 题目

有n个房子在一列直线上,现在Bob需要给房屋染色,共有k种颜色。
每个房屋染不同的颜色费用也不同,Bob希望有一种染色方案使得相邻的房屋颜色不同。
但Bob计算了使相邻房屋颜色不同的最小染色费用,发现花费非常高。
于是Bob想选择一个区间作为主题步行街,在这个区间中的所有房子必须染成同一个颜色。Bob觉得这样可能能降低总花费,但是也不想让这个步行街太长。
Bob认为步行街的长度最多为 ‘t’
但这个花费太难计算,Bob打算交给你来计算。
你能算出将这些房子进行染色的最小花费是多少吗?

费用通过一个nxk 的矩阵给出,比如costs[0][0]表示房屋0染颜色0的费用,costs[1][2]表示房屋1染颜色2的费用。
t 是一个整数,表示有最多有多少个房屋颜色相同。

房子总数: 1 <= n <= 100 
颜色总数: 1 <= k <= 100 
步行街长度上限: 1 <= t <= 10 
房屋染色费用: 1 <= cost[i][j] <= 1000

示例
样例1
输入:
costs = [[14,2,11],[11,14,5],[14,3,10]]
t = 2
输出: 10
说明:
三个屋子分别使用第1,2,1种颜色,总花费是10。
在这个样例中你不需要建造步行街。

样例2
输入:
costs = [[14,2,11],[11,14,5],[14,3,10]]
t = 2 
输出: 10
说明:
你可以在[1,2]的区间中建造一个步行街,
这样序号为12的两个房子可以染成相同颜色。
因此如果这三个房子的颜色为[2,2,1],总花费为10.
如果你在[2,3]的区间中建造一个步行街,
最小的花费是11(1+5+5),大于10,因此不是最优解。
你无法在[1,3]中建造步行街,因为步行街总长度为3,大于t。

来源:https://tianchi.aliyun.com/oj/15179470890799741/85251759933690470

2. 解题

题目意思是最多只能有一个步行街,我理解错了,以为是不限制

错误代码:

class Solution {
public:
    /**
     * @param costs: costs of paint ith house into color j
     * @param t: maximum length of street
     * @return: minimum costs of painting all houses
     */
    int paintHouseIII(vector<vector<int>> &costs, int t) {
        // Write your code here.
        int n = costs.size(), col = costs[0].size(), i, j;
        vector<vector<vector<int>>>  dp(n, vector<vector<int>>(col, vector<int>(t+1, INT_MAX)));
        // dp[i][c][k] 表示 i房子刷完了,其是 c 颜色,c 颜色连续了 k 次 的最小花费
        for(j = 0; j < col; ++j)
            dp[0][j][1] = costs[0][j];
        for(i = 1; i < n; ++i)
        {
            for(int c1 = 0; c1 < col; ++c1)
            {
                for(int c2 = 0; c2 < col; ++c2)
                {
                    if(c1 != c2)
                    {
                        for(int k = 1; k <= t; ++k)
                        {
                            if(dp[i-1][c1][k] == INT_MAX)
                                continue;
                            dp[i][c2][1] = min(dp[i][c2][1], costs[i][c2]+dp[i-1][c1][k]);
                        }
                    }
                    else
                    {
                        for(int k = 1; k < t; ++k)
                        {
                            if(dp[i-1][c1][k] == INT_MAX)
                                continue;
                            dp[i][c2][k+1] = min(dp[i][c2][k+1], costs[i][c2]+dp[i-1][c1][k]);
                        }
                    }
                    
                }
            }
        }
        int ans = INT_MAX;
        for(i = 0; i < col; ++i)
            for(j = 1; j <= t; ++j)
                ans = min(ans, dp[n-1][i][j]);
        return ans;
    }
};

参考大佬的题解

正确解:

class Solution {
public:
    /**
     * @param costs: costs of paint ith house into color j
     * @param t: maximum length of street
     * @return: minimum costs of painting all houses
     */
    int paintHouseIII(vector<vector<int>> &costs, int t) {
        // Write your code here.
        int n = costs.size(), col = costs[0].size(), i, j, k, c1, c2;
        vector<vector<vector<int>>>  dp(n, vector<vector<int>>(col, vector<int>(2, INT_MAX)));
        // dp[i][c][0 or 1] 表示 i 房子刷完 c 颜色,还没有步行街0,有步行街1,的最小花费
        for(j = 0; j < col; ++j)
            dp[0][j][0] = dp[0][j][1] = costs[0][j];//初始化
        vector<vector<int>> value(n, vector<int>(n, 0));
        for(j = 0; j < col; ++j)
        {
            for(i = 0; i < n; ++i)//房子都刷 j 颜色的花费前缀和
            {
                if(i == 0)
                    value[i][j] = costs[i][j];
                else
                    value[i][j] = value[i-1][j] + costs[i][j];
            }
        }
        for(i = 1; i < n; ++i)
        {
            for(c1 = 0; c1 < col; ++c1)
            {
                for(c2 = 0; c2 < col; ++c2)
                {
                    if(c1 != c2)//颜色不一样
                    {
                        dp[i][c2][0] = min(dp[i][c2][0], dp[i-1][c1][0]+costs[i][c2]);
                        dp[i][c2][1] = min(dp[i][c2][1], dp[i-1][c1][1]+costs[i][c2]);
                    }
                }
                //颜色一样,可以跟前面组成步行街
                for(j = i-1; j >= 0; --j)//[j, i] 区间为同一颜色 c1 的步行街
                {
                    if(i-j+1 > t)
                        break;
                    dp[i][c1][1] = min(dp[i][c1][1], dp[j][c1][0]+value[i][c1]-value[j][c1]);
                    // 								前面没有步行街0, + 加上后面都是 c1 颜色的花费
                }
            }
        }
        int ans = INT_MAX;
        for(j = 0; j < col; ++j)
            ans = min(ans, min(dp[n-1][j][0], dp[n-1][j][1]));
        return ans;
    }
};

在这里插入图片描述


我的CSDN博客地址 https://michael.blog.csdn.net/

长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!
Michael阿明

猜你喜欢

转载自blog.csdn.net/qq_21201267/article/details/108419432
今日推荐