房屋染色

题目描述:这里有n个房子在一列直线上,现在我们需要给房屋染色,分别有红色蓝色和绿色。每个房屋染不同的颜色费用也不同,你需要设计一种染色方案使得相邻的房屋颜色不同,并且费用最小。费用通过一个nx3 的矩阵给出,比如cost[0][0]表示房屋0染红色的费用,cost[1][2]表示房屋1染绿色的费用。

样例:costs = [[14,2,11],[11,14,5],[14,3,10]] return 10。房屋 0 蓝色, 房屋 1 绿色, 房屋 2 蓝色, 2 + 5 + 3 = 10


跟上一道题:“栅栏染色”一样(详见:点击打开链接),都是动态规划的问题,但是逻辑上是不同的。这道题求的是最低成本,那么不妨这么分析:对于每个房屋来说,它原本有3种染色方案,就是染红色蓝色和绿色,每一种选择都会导致它的上一个房屋不能染该颜色了(这不是一个因果关系,而是说在逻辑上,如果第i个房屋在我们设计的最佳方案中选择了其中一种,那必然会导致它的上一个房屋颜色与之不同,否则方案就是不合理的)。


举个例子,我们假设现在有n个房屋,如果最佳方案中,第n个房屋染红色,那么前n - 1个房屋就有一个最佳染色方案,这个方案肯定是要求第n - 1个房屋染蓝色或者绿色(至于具体染什么颜色,包括前n - 2个房屋的染色方案是什么,我们先不去管),那么整个染色方案最小成本就应该这样计算:


因为我们并不知道最后一个房屋怎么染色,所以,分3种情况:

1. 最后一个房屋染红色,那么第n - 1个房屋蓝色或者绿色,前n -1个房屋(包括第n - 1个)的最小染色成本我们记为record[1], record[2],那么最终的所有房屋的染色成本就是:min(record[1], record[2]) + 最后一个房屋染红色的价钱

2. 最后一个房屋染蓝色,那么第n - 1个房屋红色或者绿色,前n -1个房屋(包括第n - 1个)的最小染色成本我们记为record[0], record[2],那么最终的所有房屋的染色成本就是:min(record[0], record[2]) + 最后一个房屋染蓝色的价钱

3. 最后一个房屋染绿色,同理,我就不写了


这三种情况求出来后,再计算他们的最小值,就是本题的最优解。


用一个三元数组record记录前n个房间分别染3种颜色时的最小成本,那么状态转移方程:record[i] = cost[i] + min(record[j] + record[k]),其中,cost[i]为第n + 1个房屋染i这个颜色的成本,record[j],record[k]为不是i颜色的两种颜色。

初始状态为:record = [costs[0][0],costs[0][1], costs[0][2]]

代码如下:

class Solution:
    # @param {int[][]} costs n x 3 cost matrix
    # @return {int} an integer, the minimum cost to paint all houses
    def minCost(self, costs):

        # 处理特殊情况
        if len(costs) == 0:
            return 0

        # 初始化条件
        record = costs[0]

        for cost in costs[1:]:
            temp = []
            for i in range(3):
                temp.append(cost[i] + min(record[i - 1], record[i - 2]))
            record = temp
        return min(record)
        # Write your code here
需要注意的是,第16行用到了python语言中列表的特殊性质:a[-1]表示数组a的最后一个元素,a[-2]表示a的倒数第二个元素...以此类推。

总结一下,其实最难的点还是子问题如何“升级”,也就是状态转移方程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值