题目来源
题目描述
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
}
};
这是一个典型的序列型动态规划
序列型动态规划 VS 坐标型动态规划
- 坐标型动态规划:是一个点,假设当前状态是(x,y),那么前一个状态是(x - 1, y - 1)
- 序列型动态规划:是一条线,加入当前状态是[0…n],那么前一个状态是[0…n-1]
题目解析
- 因为相邻两栋房子不能是同样的颜色,所以它是有后效性的,所以不能用贪心算法来解决。必须用dp来讲[后效性]处理成[无后效性]
- dp本质上是一个递归,递归本质上是一个穷举。也就是说最后的一套房子一定会遍历到,而且必须要刷,只是刷的颜色不同。也就是说最后的决策是:刷红色、刷蓝色、刷绿色—》从三种决策中选出一种
动态规划
(1)确定状态
- 最优策略是花费最小的策略
- 最后一步:最优策略中房子N-1一定染成了红、蓝、绿中的一种。
- 但是因为相邻两栋房子不能是同一种颜色,所以:
- 如果最优策略中房子N-1是红色,那么房子N-2只能是蓝色或者绿色
- 如果最优策略中房子N-1是绿色,那么房子N-2只能是蓝色或者红色
- 如果最优策略中房子N-1是蓝色,那么房子N-2只能是绿色或者红色
- 套用以前的思路:
- 记录漆[0…N-1]栋房子的最小花费,就也需要记录漆[0…N-2]栋房子的最小花费
- 根据套路:
- 对于
f
(
N
)
f(N)
f(N),它记录了
[
0...
N
−
1
]
[0...N-1]
[0...N−1]房子的最小花费,f(N)返回最小花费
- f ( N ) = c o s t [ N − 1 ] + f ( N − 1 ) , c o s t [ N − 1 ] f(N) = cost[N - 1] + f(N - 1), cost[N - 1] f(N)=cost[N−1]+f(N−1),cost[N−1]为油漆第N-1栋房子是红色、蓝色、绿色中其中一个方案的最小花费
- f ( N − 1 ) = c o s t [ N − 2 ] + f ( N − 1 ) , c o s t [ N − 2 ] f(N-1) = cost[N - 2] + f(N - 1), cost[N - 2] f(N−1)=cost[N−2]+f(N−1),cost[N−2]为油漆第N-2栋房子是红色、蓝色、绿色中其中一个方案的最小花费
- 因为我们没有记录下来第N-2栋房子到底是什么颜色,所以房子N-2有可能和房子N-1撞色
- 对于
f
(
N
)
f(N)
f(N),它记录了
[
0...
N
−
1
]
[0...N-1]
[0...N−1]房子的最小花费,f(N)返回最小花费
- 怎么解决。记录下颜色就可以了。
- 如果要求最后的问题(油漆[0…N-1]房子的最小花费),就要知道:
- 油漆[0…N-2]房子的最小花费,并且房子N-2是蓝色的花费&&
- 油漆[0…N-2]房子的最小花费,并且房子N-2是绿色的花费&&
- 油漆[0…N-2]房子的最小花费,并且房子N-2是红色的花费
- 这样,我们就回答上面的问题了
- 如果最优策略中房子N-1是红色,那么房子N-2只能是蓝色或者绿色
- 如果最优策略中房子N-1是绿色,那么房子N-2只能是蓝色或者红色
- 如果最优策略中房子N-1是蓝色,那么房子N-2只能是绿色或者红色
- 即:求油漆[0…N-1]房子的最小花费并且房子N-1是红色、蓝色、绿色的最小花费,需要知道油漆[0…N-2]房子的最小花费并且房子N2是红色、蓝色、绿色的最小花费
- 如果要求最后的问题(油漆[0…N-1]房子的最小花费),就要知道:
- 定义状态:设油漆[0…i-1]房子的最小花费并且房子i-1是红色、蓝色、绿色的最小花费分别为
f[i][0]、f[i][1]、f[i][2]
(2)定义转移方程
- 已知:设油漆[0…i-1]房子的最小花费并且房子i-1是红色、蓝色、绿色的最小花费分别为
f[i][0]、f[i][1]、f[i][2]
- 那么:
(3)初始条件和边界条件:
- 初始条件: f[0][0] = f[0][1] = f[0][2] = 0,即不油漆任何房子的花费 (f[0][i]表示[0…-1]的数组)
- 无边界条件
(4)计算顺序
- 从上到下
- 初始化 f[0][0] = f[0][1] = f[0][2] ,没有房子
- 计算:f[1][0]、f[1][1]、F[2][1],油漆到第1栋房子
- …
- 计算:f[N-1][0]、f[N-1][1]、F[N-1][1],油漆到第N-1栋房子
- 计算:f[N][0]、f[N][1]、F[N][1] ,油漆到第N栋房子
- 返回值:std::min(f[N][0]、f[N][1]、F[N][1]);
class Solution {
public:
int minCost(vector<vector<int>>& costs) {
if (costs.empty() || costs[0].empty()) return 0;
vector<vector<int>> dp = costs;
for (int i = 1; i < dp.size(); ++i) {
dp[i][0] += min(dp[i - 1][1], dp[i - 1][2]);
dp[i][1] += min(dp[i - 1][0], dp[i - 1][2]);
dp[i][2] += min(dp[i - 1][0], dp[i - 1][1]);
}
return min(min(dp.back()[0], dp.back()[1]), dp.back()[2]);
}
};