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 have 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.
Given an array houses, an m x n matrix cost and an integer target where:
houses[i]: is the color of the house i, and 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 exactlytargetneighborhoods. If it is 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.
Example 2:
1
2
3
4
5
6
7
Input:
houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
Output:
11
Explanation: Some houses are already painted, Paint the houses of this way [2,2,1,2,2]
This array contains target = 3 neighborhoods, [{2,2}, {1}, {2,2}].
Cost of paint the first and last house (10 + 1) = 11.
Example 3:
1
2
3
4
5
Input:
houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3
Output:
-1
Explanation: Houses are already painted with a total of 4 neighborhoods [{3},{1},{2},{3}] different of target = 3.
This problem can be solved using backtracking with memoization. The key idea is to fill unpainted houses (slots with value 0) with available colors, aiming to form exactly target neighborhoods at minimum cost. At each step, we track the current neighborhood count and previous color, and make choices that either continue the current neighborhood or start a new one. Memoization helps avoid redundant calculations for repeated subproblems.
⏰ Time complexity:O(m * n * target * n) — For each house (m), we try every color (n) and every possible remaining target (target), and for each, we may try all colors again in recursion. Memoization ensures each state (idx, target, prevColor) is computed only once.
🧺 Space complexity:O(m * n * target) — The memoization table stores results for each combination of house index, target, and previous color.
classSolution {
public:int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
vector<vector<vector<long>>> memo(m, vector<vector<long>>(target+1, vector<long>(n+1, -1)));
function<long(int,int,int)> dfs = [&](int idx, int t, int prev) ->long {
if (idx == m) return t ==0?0: INT_MAX;
if (t <0) return INT_MAX;
if (memo[idx][t][prev] !=-1) return memo[idx][t][prev];
long ans = INT_MAX;
if (houses[idx] ==0) {
for (int color =1; color <= n; ++color) {
long c = cost[idx][color-1] + dfs(idx+1, t-(color!=prev), color);
ans = min(ans, c);
}
} else {
ans = dfs(idx+1, t-(houses[idx]!=prev), houses[idx]);
}
return memo[idx][t][prev] = ans;
};
long res = dfs(0, target, 0);
return res == INT_MAX ?-1: (int)res;
}
};
classSolution {
publicintminCost(int[] houses, int[][] cost, int m, int n, int target) {
long[][][] memo =newlong[m][target + 1][n + 1];
for (int i = 0; i < m; i++)
for (int j = 0; j < target + 1; j++)
Arrays.fill(memo[i][j], -1);
long ans = dfs(houses, cost, m, n, target, 0, 0, memo);
return ans == Integer.MAX_VALUE?-1 : (int)ans;
}
privatelongdfs(int[] houses, int[][] cost, int m, int n, int target, int idx, int prevIdx, long[][][] memo) {
if (idx == m) return target == 0 ? 0 : Integer.MAX_VALUE;
if (target < 0) return Integer.MAX_VALUE;
if (memo[idx][target][prevIdx]!=-1) return memo[idx][target][prevIdx];
long ans = Integer.MAX_VALUE;
if (houses[idx]== 0) {
for (int j = 1; j <= n; j++) {
ans = Math.min(ans, cost[idx][j - 1]+ dfs(houses, cost, m, n, target - ((j != prevIdx) ? 1 : 0), idx + 1, j, memo));
}
} else {
ans = dfs(houses, cost, m, n, target - ((houses[idx]!= prevIdx) ? 1 : 0), idx + 1, houses[idx], memo);
}
memo[idx][target][prevIdx]= ans;
return ans;
}
}
classSolution {
funminCost(houses: IntArray, cost: Array<IntArray>, m: Int, n: Int, target: Int): Int {
val memo = Array(m) { Array(target+1) { LongArray(n+1) { -1L } } }
fundfs(idx: Int, t: Int, prev: Int): Long {
if (idx == m) returnif (t ==0) 0LelseLong.MAX_VALUE
if (t < 0) returnLong.MAX_VALUE
if (memo[idx][t][prev] != -1L) return memo[idx][t][prev]
var ans = Long.MAX_VALUE
if (houses[idx] ==0) {
for (color in1..n) {
val c = cost[idx][color-1] + dfs(idx+1, t - if (color != prev) 1else0, color)
ans = minOf(ans, c)
}
} else {
ans = dfs(idx+1, t - if (houses[idx] != prev) 1else0, houses[idx])
}
memo[idx][t][prev] = ans
return ans
}
val res = dfs(0, target, 0)
returnif (res ==Long.MAX_VALUE) -1else res.toInt()
}
}
classSolution:
defminCost(self, houses: list[int], cost: list[list[int]], m: int, n: int, target: int) -> int:
memo = [[[Nonefor _ in range(n+1)] for _ in range(target+1)] for _ in range(m)]
defdfs(idx: int, t: int, prev: int) -> int:
if idx == m:
return0if t ==0else float('inf')
if t <0:
return float('inf')
if memo[idx][t][prev] isnotNone:
return memo[idx][t][prev]
ans = float('inf')
if houses[idx] ==0:
for color in range(1, n+1):
c = cost[idx][color-1] + dfs(idx+1, t-(color!=prev), color)
ans = min(ans, c)
else:
ans = dfs(idx+1, t-(houses[idx]!=prev), houses[idx])
memo[idx][t][prev] = ans
return ans
res = dfs(0, target, 0)
return-1if res == float('inf') else res
impl Solution {
pubfnmin_cost(houses: Vec<i32>, cost: Vec<Vec<i32>>, m: i32, n: i32, target: i32) -> i32 {
let m = m asusize;
let n = n asusize;
let target = target asusize;
letmut memo =vec![vec![vec![-1i64; n+1]; target+1]; m];
fndfs(idx: usize, t: usize, prev: usize, houses: &Vec<i32>, cost: &Vec<Vec<i32>>, m: usize, n: usize, target: usize, memo: &mut Vec<Vec<Vec<i64>>>) -> i64 {
if idx == m { returnif t ==0 { 0 } else { i64::MAX }; }
if t > target { returni64::MAX; }
if memo[idx][t][prev] !=-1 { return memo[idx][t][prev]; }
letmut ans =i64::MAX;
if houses[idx] ==0 {
for color in1..=n {
let c = cost[idx][color-1] asi64+ dfs(idx+1, t +if color != prev { 1 } else { 0 }, color, houses, cost, m, n, target, memo);
if c < ans { ans = c; }
}
} else {
ans = dfs(idx+1, t +if houses[idx] asusize!= prev { 1 } else { 0 }, houses[idx] asusize, houses, cost, m, n, target, memo);
}
memo[idx][t][prev] = ans;
ans
}
let res = dfs(0, 0, 0, &houses, &cost, m, n, target, &mut memo);
if res ==i64::MAX { -1 } else { res asi32 }
}
}
This method uses dynamic programming to iteratively build up solutions for each house, color, and neighborhood count. Instead of recursion, we fill a 3D DP table where each entry represents the minimum cost to paint up to a certain house with a given color and number of neighborhoods. By considering all possible transitions from previous states, we ensure that all combinations are explored efficiently.
⏰ Time complexity:O(m * n^2 * target) — For each house (m), color (n), and target (target), we try every previous color (n), leading to an extra factor of n in the innermost loop.
🧺 Space complexity:O(m * n * target) — The DP table stores results for each combination of house, color, and target.
classSolution {
public:int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
vector<vector<vector<int>>> dp(m, vector<vector<int>>(n, vector<int>(target+1, -1)));
for (int i =0; i < n; ++i) {
if (houses[0] ==0) dp[0][i][1] = cost[0][i];
elseif (houses[0] == i+1) dp[0][i][1] =0;
}
for (int i =1; i < m; ++i) {
for (int t =1; t <= target && t <= i+1; ++t) {
for (int j =0; j < n; ++j) {
if (houses[i] !=0&& houses[i] != j+1) continue;
int costToPaint = houses[i] == j+1?0: cost[i][j];
for (int k =0; k < n; ++k) {
if (j == k && dp[i-1][k][t] !=-1) {
int val = costToPaint + dp[i-1][k][t];
dp[i][j][t] = dp[i][j][t] ==-1? val : min(dp[i][j][t], val);
} elseif (j != k && dp[i-1][k][t-1] !=-1) {
int val = costToPaint + dp[i-1][k][t-1];
dp[i][j][t] = dp[i][j][t] ==-1? val : min(dp[i][j][t], val);
}
}
}
}
}
int ans =-1;
for (int i =0; i < n; ++i) {
if (dp[m-1][i][target] !=-1) ans = ans ==-1? dp[m-1][i][target] : min(ans, dp[m-1][i][target]);
}
return ans;
}
};
classSolution {
publicintminCost(int[] houses, int[][] cost, int m, int n, int target) {
int[][][] dp =newint[m][n][target+1];
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
for(int k=0; k <= target; k++)
dp[i][j][k]=-1;
for(int i = 0; i < n; i++) {
if (houses[0]== 0) dp[0][i][1]=cost[0][i];
elseif (houses[0]== i+1) dp[0][i][1]= 0;
}
for(int i = 1; i < m; i++) {
for(int t = 1; t <= target && t <= i+1; t++) {
for(int j = 0; j < n; j++) {
if (houses[i]!= 0 && houses[i]!= j+1) continue;
int costToPaint = houses[i]==j+1 ? 0 : cost[i][j];
for(int k = 0; k < n; k++) {
if (j == k && dp[i-1][k][t]!=-1) {
int val = costToPaint + dp[i-1][k][t];
dp[i][j][t]= dp[i][j][t]==-1 ? val : Math.min(dp[i][j][t], val);
}
elseif (j != k && dp[i-1][k][t-1]!=-1) {
int val = costToPaint + dp[i-1][k][t-1];
dp[i][j][t]= dp[i][j][t]==-1 ? val : Math.min(dp[i][j][t], val);
}
}
}
}
}
int ans =-1;
for(int i = 0; i < n; i++) {
if (dp[m-1][i][target]!=-1) ans = ans ==-1 ? dp[m-1][i][target] : Math.min(ans,dp[m-1][i][target]);
}
return ans;
}
}
classSolution {
funminCost(houses: IntArray, cost: Array<IntArray>, m: Int, n: Int, target: Int): Int {
val dp = Array(m) { Array(n) { IntArray(target+1) { -1 } } }
for (i in0 until n) {
if (houses[0] ==0) dp[0][i][1] = cost[0][i]
elseif (houses[0] == i+1) dp[0][i][1] = 0 }
for (i in1 until m) {
for (t in1..target.coerceAtMost(i+1)) {
for (j in0 until n) {
if (houses[i] !=0&& houses[i] != j+1) continueval costToPaint = if (houses[i] == j+1) 0else cost[i][j]
for (k in0 until n) {
if (j == k && dp[i-1][k][t] != -1) {
val v = costToPaint + dp[i-1][k][t]
dp[i][j][t] = if (dp[i][j][t] == -1) v else minOf(dp[i][j][t], v)
} elseif (j != k && t > 0&& dp[i-1][k][t-1] != -1) {
val v = costToPaint + dp[i-1][k][t-1]
dp[i][j][t] = if (dp[i][j][t] == -1) v else minOf(dp[i][j][t], v)
}
}
}
}
}
var ans = -1for (i in0 until n) {
if (dp[m-1][i][target] != -1) ans = if (ans == -1) dp[m-1][i][target] else minOf(ans, dp[m-1][i][target])
}
return ans
}
}
classSolution:
defminCost(self, houses: list[int], cost: list[list[int]], m: int, n: int, target: int) -> int:
dp = [[[-1for _ in range(target+1)] for _ in range(n)] for _ in range(m)]
for i in range(n):
if houses[0] ==0:
dp[0][i][1] = cost[0][i]
elif houses[0] == i+1:
dp[0][i][1] =0for i in range(1, m):
for t in range(1, min(target, i+1)+1):
for j in range(n):
if houses[i] !=0and houses[i] != j+1:
continue costToPaint =0if houses[i] == j+1else cost[i][j]
for k in range(n):
if j == k and dp[i-1][k][t] !=-1:
val = costToPaint + dp[i-1][k][t]
dp[i][j][t] = val if dp[i][j][t] ==-1else min(dp[i][j][t], val)
elif j != k and t >0and dp[i-1][k][t-1] !=-1:
val = costToPaint + dp[i-1][k][t-1]
dp[i][j][t] = val if dp[i][j][t] ==-1else min(dp[i][j][t], val)
ans =-1for i in range(n):
if dp[m-1][i][target] !=-1:
ans = dp[m-1][i][target] if ans ==-1else min(ans, dp[m-1][i][target])
return ans