https://leetcode-cn.com/problems/paint-house-iii/
这个动态规划,没太想明白,是怎么能想出来这样动态规划的
class Solution {
public:
const int INF = 0x3f3f3f3f;
int f[105][25][105];
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
for(int i = 0; i <= m; i++){
for(int j = 0; j <= n; j++){
f[i][j][0] = INF;//0是不可能
}
}
//动态规划的特点之一是在于,每次都是从前向后递推,同时不会修改任何和当前ijk无关的数值
for(int i = 1; i <= m; i++){
int color = houses[i - 1];//当前颜色
for(int j = 1; j <= n;j++){
for(int k = 1; k <= target; k++){//最多到达target
if(k > i){//明显不合理跳出
f[i][j][k] = INF;
continue;
}
//第i个房间已经上色
if(color != 0){
if(j == color){
int cur = INF;
for(int p = 1; p <= n; p++){
if(p != j){ //颜色不同
cur = min(cur,f[i - 1][p][k - 1]);//颜色不相同,则第三元素取值为k-1
}
}
f[i][j][k] = min(cur,f[i - 1][j][k]);//因为颜色相同,则第三元素取值为k
}//颜色相同
else f[i][j][k] = INF; //颜色不同则无效
}
else{ //第i个房间未上色
int u = cost[i - 1][j - 1];
int cur = INF;
for(int p = 1; p <= n; p++){
if(p != j){
cur = min(cur,f[i - 1][p][k - 1] + u);
}
}
f[i][j][k] = min(cur,f[i - 1][j][k] + u);
}
}
}
}
int ans = INF;
for(int i = 1; i <= n; i++){
ans = min(ans,f[m][i][target]);//从所有的涂色方法中中选择一个最小的输出
}
return ans == INF ? -1 : ans;
}
};
f[i][j][k]表示从0~i的区间里面,最后一个颜色是j,此时形成状态为k个街区情形的最小花费。
我早有预感,状态转移方程可能是三位的,这样来清晰的说明一下,首先必须包含一个k是用来表示几个街区的,其次必须有一个或者两个位是用来表示范围的[i,j]或者[0,i].
那么究竟是哪一种,通过看实际意义来得到。还有一位是表示颜色的。
这样梳理的话,倒是感觉清晰了不少。
状态转移方程:
h
o
u
s
e
s
[
i
]
=
=
0
d
p
[
i
]
[
j
]
[
k
]
=
m
i
n
p
!
=
j
{
d
p
[
i
−
1
]
[
p
]
[
k
−
1
]
+
c
o
s
t
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
]
[
k
]
+
c
o
s
t
[
i
]
[
j
]
}
houses[i]==0\\ dp[i][j][k]=min_{ p!=j}\{dp[i-1][p][k-1]+cost[i][j],dp[i-1][j][k]+cost[i][j] \}
houses[i]==0dp[i][j][k]=minp!=j{dp[i−1][p][k−1]+cost[i][j],dp[i−1][j][k]+cost[i][j]}
h
o
u
s
e
s
[
i
]
!
=
0
d
p
[
i
]
[
j
]
[
k
]
=
m
i
n
p
!
=
j
{
d
p
[
i
−
1
]
[
p
]
[
k
−
1
]
,
d
p
[
i
−
1
]
[
j
]
[
k
]
}
houses[i]!=0\\ dp[i][j][k]=min_{ p!=j}\{dp[i-1][p][k-1],dp[i-1][j][k] \}
houses[i]!=0dp[i][j][k]=minp!=j{dp[i−1][p][k−1],dp[i−1][j][k]}
这样通过总结就可以得到,两者其实只是差了一个cost的值。
所以,可以进一步优化代码。
class Solution {
public:
const int INF = 0x3f3f3f3f;
int f[105][25][105];
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
for(int i = 0; i <= m; i++){
for(int j = 0; j <= n; j++){
f[i][j][0] = INF;//0是不可能
}
}
for(int i = 1; i <= m; i++){
int color = houses[i - 1];//当前颜色
for(int j = 1; j <= n;j++){
for(int k = 1; k <= target; k++){//最多到达target
if(k > i||j!=color&&color!=0){//明显不合理跳出
f[i][j][k] = INF;
continue;
}
int u = cost[i - 1][j - 1];
int cur = INF;
if(color!=0) u=0;
for(int p = 1; p <= n; p++){
if(p != j){
cur = min(cur,f[i - 1][p][k - 1]+u);
}
}
f[i][j][k] = min(cur,f[i - 1][j][k]+u);
}
}
}
int ans = INF;
for(int i = 1; i <= n; i++)
ans = min(ans,f[m][i][target]);
return ans == INF ? -1 : ans;
}
};
so,希望我的努力有效且真实。