题目描述:这里有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的倒数第二个元素...以此类推。
总结一下,其实最难的点还是子问题如何“升级”,也就是状态转移方程