Paint House III

hard dp 3d state

Problem

A street has m houses in a row, and every house must end up in one of n colors numbered 1..n. Some houses were painted last summer: houses[i] is that color, or 0 if house i still needs paint — and an already-painted house must not be repainted. Painting house i with color j costs cost[i][j].

A neighborhood is a maximal block of consecutive houses sharing one color (so [1,2,2,1] has 3 neighborhoods). Return the minimum total cost to paint all remaining houses so the street has exactly target neighborhoods, or −1 if that is impossible.

Inputhouses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
Output9
Colors [1,2,2,1,1] form the blocks {1}, {2,2}, {1,1} — exactly 3 neighborhoods — for 1+1+1+1+5 = 9.

def min_cost(houses, cost, m, n, target):
    INF = float("inf")
    # dp[j][k]: cheapest with house i in color j+1 and k neighborhoods
    dp = [[INF] * (target + 1) for _ in range(n)]
    for j in range(n):
        if houses[0] == 0:
            dp[j][1] = cost[0][j]
        elif houses[0] == j + 1:
            dp[j][1] = 0
    for i in range(1, m):
        ndp = [[INF] * (target + 1) for _ in range(n)]
        for j in range(n):
            if houses[i] and houses[i] != j + 1:
                continue
            paint = 0 if houses[i] else cost[i][j]
            for k in range(1, target + 1):
                same = dp[j][k]
                diff = min((dp[p][k - 1] for p in range(n) if p != j), default=INF)
                best = min(same, diff)
                if best < INF:
                    ndp[j][k] = best + paint
        dp = ndp
    ans = min(dp[j][target] for j in range(n))
    return -1 if ans == INF else ans
function minCost(houses, cost, m, n, target) {
  const INF = Infinity;
  // dp[j][k]: cheapest with house i in color j+1 and k neighborhoods
  let dp = Array.from({ length: n }, () => new Array(target + 1).fill(INF));
  for (let j = 0; j < n; j++) {
    if (houses[0] === 0) dp[j][1] = cost[0][j];
    else if (houses[0] === j + 1) dp[j][1] = 0;
  }
  for (let i = 1; i < m; i++) {
    const ndp = Array.from({ length: n }, () => new Array(target + 1).fill(INF));
    for (let j = 0; j < n; j++) {
      if (houses[i] !== 0 && houses[i] !== j + 1) continue;
      const paint = houses[i] ? 0 : cost[i][j];
      for (let k = 1; k <= target; k++) {
        let best = dp[j][k];
        for (let p = 0; p < n; p++)
          if (p !== j && dp[p][k - 1] < best) best = dp[p][k - 1];
        if (best < INF) ndp[j][k] = best + paint;
      }
    }
    dp = ndp;
  }
  let ans = INF;
  for (let j = 0; j < n; j++) ans = Math.min(ans, dp[j][target]);
  return ans === INF ? -1 : ans;
}
int minCost(int[] houses, int[][] cost, int m, int n, int target) {
    final int INF = Integer.MAX_VALUE / 2;
    // dp[j][k]: cheapest with house i in color j+1 and k neighborhoods
    int[][] dp = new int[n][target + 1];
    for (int[] row : dp) Arrays.fill(row, INF);
    for (int j = 0; j < n; j++) {
        if (houses[0] == 0) dp[j][1] = cost[0][j];
        else if (houses[0] == j + 1) dp[j][1] = 0;
    }
    for (int i = 1; i < m; i++) {
        int[][] ndp = new int[n][target + 1];
        for (int[] row : ndp) Arrays.fill(row, INF);
        for (int j = 0; j < n; j++) {
            if (houses[i] != 0 && houses[i] != j + 1) continue;
            int paint = houses[i] != 0 ? 0 : cost[i][j];
            for (int k = 1; k <= target; k++) {
                int best = dp[j][k];
                for (int p = 0; p < n; p++)
                    if (p != j) best = Math.min(best, dp[p][k - 1]);
                if (best < INF) ndp[j][k] = best + paint;
            }
        }
        dp = ndp;
    }
    int ans = INF;
    for (int j = 0; j < n; j++) ans = Math.min(ans, dp[j][target]);
    return ans == INF ? -1 : ans;
}
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
    const int INF = 1e9;
    // dp[j][k]: cheapest with house i in color j+1 and k neighborhoods
    vector<vector<int>> dp(n, vector<int>(target + 1, INF));
    for (int j = 0; j < n; j++) {
        if (houses[0] == 0) dp[j][1] = cost[0][j];
        else if (houses[0] == j + 1) dp[j][1] = 0;
    }
    for (int i = 1; i < m; i++) {
        vector<vector<int>> ndp(n, vector<int>(target + 1, INF));
        for (int j = 0; j < n; j++) {
            if (houses[i] != 0 && houses[i] != j + 1) continue;
            int paint = houses[i] ? 0 : cost[i][j];
            for (int k = 1; k <= target; k++) {
                int best = dp[j][k];
                for (int p = 0; p < n; p++)
                    if (p != j) best = min(best, dp[p][k - 1]);
                if (best < INF) ndp[j][k] = best + paint;
            }
        }
        dp = ndp;
    }
    int ans = INF;
    for (int j = 0; j < n; j++) ans = min(ans, dp[j][target]);
    return ans == INF ? -1 : ans;
}
Time: O(m · n² · target) Space: O(n · target)