一、Problem
There is a row of m houses in a small city, each house must be painted with one of the n colors (labeled from 1 to n), some houses that has been painted last summer should not be painted again.
A neighborhood is a maximal group of continuous houses that are painted with the same color. (For example: houses = [1,2,2,3,3,2,1,1] contains 5 neighborhoods [{1}, {2,2}, {3,3}, {2}, {1,1}]).
Given an array houses, an m * n matrix cost and an integer target where:
houses[i]: is the color of the house i, 0 if the house is not painted yet.
cost[i][j]: is the cost of paint the house i with the color j+1.
Return the minimum cost of painting all the remaining houses in such a way that there are exactly target neighborhoods, if not possible return -1.
Input: houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
Output: 9
Explanation: Paint houses of this way [1,2,2,1,1]
This array contains target = 3 neighborhoods, [{1}, {2,2}, {1,1}].
Cost of paint all houses (1 + 1 + 1 + 1 + 5) = 9.
Constraints:
m == houses.length == cost.length
n == cost[i].length
1 <= m <= 100
1 <= n <= 20
1 <= target <= m
0 <= houses[i] <= n
1 <= cost[i][j] <= 10^4
二、Solution
方法一:記憶化搜索
不要被題目過多的條件弄昏頭腦,整理一下信息其實講的是:給 m 個房子塗上色,然後讓相同顏色若干房子形成一個街道,用盡量少的代價去將 m 個房子填圖顏色,最後形成 target 個街道。
- 已經被填塗顏色的房子不能再被填塗,這句話告訴我們:
house[i] != 0
時,cost[i][house[i]-1] = 0
,而其它顏色可初始化爲 INF,這樣就可以避免將房子 塗成其它顏色。 - 表示將前 個房子塗成顏色 形成 個街道的最少花費。
- 對於第 個房子,我們可以選擇填塗爲顏色 ,也可以塗成其它顏色:
- 塗成顏色 k,那麼街區劃分數量不變
- 塗成其它顏色,那麼街區劃分數量 - 1
class Solution {
int n, INF = 0x3f3f3f3f, cs[][], f[][][];
int dfs(int i, int j, int k) {
if (j == 0 || j > i + 1) return INF;
if (i == 0) return cs[0][k];
if (f[i][j][k] != 0) return f[i][j][k];
int min = INF;
for (int c = 0; c < n; c++) if (c != k) {
min = Math.min(min, cs[i][k] + dfs(i-1, j-1, c));
}
min = Math.min(min, dfs(i-1, j, k) + cs[i][k]);
return f[i][j][k] = min;
}
public int minCost(int[] hs, int[][] cost, int m, int n, int tar) {
cs = cost;
this.n = n;
int min = INF;
for (int i = 0; i < hs.length; i++) {
if (hs[i] != 0) {
Arrays.fill(cs[i], INF);
cs[i][hs[i]-1] = 0;
}
}
f = new int[m][tar+1][n];
for (int c = 0; c < n; c++)
min = Math.min(min, dfs(m-1, tar, c));
return min == INF ? -1 : min;
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
因爲遞歸是自頂向下的,所以只有遇到邊界纔會逐層返回,自行對比下與 dp 的異同
方法二:dp
- 定義狀態:
- 表示將前 個房子塗成顏色 形成 個街道的最少花費
- 思考初始化:
- 將第 0 個房子塗成顏色 c 形成 1 個街道時的最小花費只能是
- 思考狀態轉移方程:
for (c in n),f[i][j][k] = min(f[i-1][j][k] + cost[i][k], f[i][j-1][k] + cost[i][c]
對於第 個房子,可如果塗成顏色與前 個房子相同的顏色 ,然後不劃分當前街區;也可以塗成與第 房子不同的顏色,然後劃分新街區。
- 思考輸出: 表示第 m 間房子塗成顏色 的最小花費
class Solution {
public int minCost(int[] hs, int[][] cs, int m, int n, int tar) {
int INF = 0x3f3f3f3f;
for (int i = 0; i < m; i++) if (hs[i] != 0) {
Arrays.fill(cs[i], INF);
cs[i][hs[i]-1] = 0;
}
int res = INF, f[][][] = new int[m][tar+1][n];
for (int i = 0; i < m; i++)
for (int j = 0; j <= tar; j++)
for (int k = 0; k < n; k++)
f[i][j][k] = INF;
for (int k = 0; k < n; k++)
f[0][1][k] = cs[0][k];
for (int i = 1; i < m; i++)
for (int j = 1; j <= Math.min(i+1, tar); j++)
for (int k = 0; k < n; k++) {
int min = INF;
for (int c = 0; c < n; c++) if (c != k) {
min = Math.min(min, f[i-1][j-1][c] + cs[i][k]);
}
f[i][j][k] = Math.min(min, f[i-1][j][k] + cs[i][k]);
}
for (int k = 0; k < n; k++) if (f[m-1][tar][k] < res) {
res = f[m-1][tar][k];
}
return res == INF ? -1 : res;
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,