题目描述
这里有n个房子在一列直线上,现在我们需要给房屋染色,分别有红色蓝色和绿色。每个房屋染不同的颜色费用也不同,你需要设计一种染色方案使得相邻的房屋颜色不同,并且费用最小,返回最小的费用。
费用通过一个nx3 的矩阵给出,比如cost[0][0]表示房屋0染红色的费用,cost[1][2]表示房屋1染绿色的费用,依此类推。找到油漆所有房子的最低成本。
样例
样例1:
输入: [[14,2,11],[11,14,5],[14,3,10]]
输出: 10
解释: 第一个屋子染蓝色,第二个染绿色,第三个染蓝色,最小花费:2 + 5 + 3 = 10.
样例 2:
输入: [[1,2,3],[1,4,6]]
输出: 3
思路分析
审题时看到需要求的是其最小费用,并且有n个房子在一列直线上,说明是一串序列的问题求最值,通常的思路是贪心算法以及动态规划,这里采用动态规划。
- 第一步需要确认状态
从最后一种情况入手,假设染了n个房子,因此当我们染第n个房子的时候,前n-1个房子的最小费用+第n个房子的染色费用就是我们需要的总最小费用。
也就是说,通常状态下,染第i+1个房子,前i个房子最小费用+当前房子染色费用即为目前为止的最小费用。假设f[i]为染i+1个房子的最小费用,而f[i-1]则为前i个房子的最小费用(因为i是从0开始的),cost[i-1]为当前房子所需要的染色费用,则我们可以得到方程:
f[i] = f[i-1] + cost[i-1]
但是发现有个条件:有三种颜色并且相邻的房屋颜色不同,因此无法确定状态,解决的方法是直接记录下来,即分别记录下三种颜色时的状态.
设f[i][0], f[i][1], f[i][2]为染了前i个房子并且房子i-1是红色、蓝色、绿色的状态,因此可以确定动态规划方程:
f[i][0] = min ( f[i-1][1] + cost[i-1][0], f[i-1][2] + cost[i-1][0] )
f[i][1] = min ( f[i-1][0] + cost[i-1][1], f[i-1][2] + cost[i-1][1] )
f[i][2] = min ( f[i-1][0] + cost[i-1][2], f[i-1][1] + cost[i-1][2] )
- 确定初始条件和边界条件
由于是序列型,因此并不需要考虑边界条件,而初始条件为当i等于0时,说明前0个房子染色,因此总费用为0,即
f[0][0] = f[0][1] = f[0][2] = 0
- 计算顺序(填表顺序)
直接升序填表即可
4.返回表格的最后一个元素即为结果
C++代码:
class Solution {
public:
/**
* @param costs: n x 3 cost matrix
* @return: An integer, the minimum cost to paint all houses
*/
int minCost(vector<vector<int>> &costs) {
// write your code here
int n = costs.size();
if(n == 0){
return 0;
}
int f[n+1][3];
f[0][0] = f[0][1] = f[0][2] = 0; //边界条件
for(int i=1; i<=n; i++){
for(int j=0; j<3; j++){
f[i][j] = INT_MAX; //小技巧:先手设为最大值,便于得到最小值
for(int k=0; k<3; k++){
if(j != k){
if(f[i-1][k]+costs[i-1][j] < f[i][j]){
f[i][j] = f[i-1][k]+costs[i-1][j];
}
}
}
}
}
//返回最小值
int res = f[n][0];
if(res > f[n][1]){
res = f[n][1];
}
if(res > f[n][2]){
res = f[n][2];
}
return res;
}
};