Program to find minimum cost for painting houses in Python

Suppose there is an array of size m representing m houses in a small city. Each house must be painted with one of the n colors (labeled from 1 to n). Some houses are already painted, so no need to paint them again. Houses colored with the same adjacent color form a neighborhood.

We have the array houses, where houses[i] represents the color of house i. If the color value is 0, the house is not colored yet. We have another array called cost, which is a 2D array where cost[i][j] represents the cost to color house i with color j+1. We also have a target value representing the exact number of neighborhoods we want.

We need to find the minimum cost to paint all remaining houses such that there are exactly target neighborhoods. If no solution exists, return -1.

Problem Example

If houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], n = 2, and target = 3, the output should be 11. We can paint the houses as [2,2,1,2,2], creating three neighborhoods: [{2,2}, {1}, {2,2}]. The cost to paint the first and last house is 10 + 1 = 11.

Algorithm Steps

We'll use dynamic programming with recursion ?

  • Define a helper function that takes current house index, previous color, and current group count

  • If we've processed all houses, return 0 if group count equals target, otherwise return infinity

  • If current house is already painted, recurse with that color

  • If current house needs painting, try all possible colors and choose minimum cost

Implementation

def solve(houses, cost, n, target):
    m = len(houses)
    
    def helper(i, p_col, grp):
        # Base case: all houses processed
        if i == m:
            return 0 if grp == target else float('inf')
        
        # House already painted
        if houses[i] != 0:
            # New neighborhood if color changes
            new_grp = grp + (1 if p_col != houses[i] else 0)
            return helper(i + 1, houses[i], new_grp)
        
        # Try all colors for unpainted house
        total = float('inf')
        for col in range(1, n + 1):
            paint_cost = cost[i][col - 1]
            new_grp = grp + (1 if p_col != col else 0)
            total = min(total, paint_cost + helper(i + 1, col, new_grp))
        
        return total
    
    # Start with house 0, no previous color (-1), 0 groups
    ans = helper(0, -1, 0)
    return ans if ans != float('inf') else -1

# Test the solution
houses = [0, 2, 1, 2, 0]
cost = [[1, 10], [10, 1], [10, 1], [1, 10], [5, 1]]
n = 2
target = 3

result = solve(houses, cost, n, target)
print(f"Minimum cost: {result}")
Minimum cost: 11

How It Works

The algorithm uses recursion with three parameters ?

  • i: Current house index being processed

  • p_col: Previous house color (to detect neighborhood boundaries)

  • grp: Current number of neighborhoods formed

A new neighborhood is created when the current house color differs from the previous house color. The algorithm explores all possible color combinations and returns the minimum cost that achieves exactly the target number of neighborhoods.

Optimized Version with Memoization

def solve_optimized(houses, cost, n, target):
    m = len(houses)
    memo = {}
    
    def helper(i, p_col, grp):
        # Memoization key
        key = (i, p_col, grp)
        if key in memo:
            return memo[key]
        
        # Base case
        if i == m:
            result = 0 if grp == target else float('inf')
            memo[key] = result
            return result
        
        # House already painted
        if houses[i] != 0:
            new_grp = grp + (1 if p_col != houses[i] else 0)
            result = helper(i + 1, houses[i], new_grp)
            memo[key] = result
            return result
        
        # Try all colors
        total = float('inf')
        for col in range(1, n + 1):
            paint_cost = cost[i][col - 1]
            new_grp = grp + (1 if p_col != col else 0)
            total = min(total, paint_cost + helper(i + 1, col, new_grp))
        
        memo[key] = total
        return total
    
    ans = helper(0, -1, 0)
    return ans if ans != float('inf') else -1

# Test optimized version
result_opt = solve_optimized(houses, cost, n, target)
print(f"Optimized result: {result_opt}")
Optimized result: 11

Conclusion

This dynamic programming solution efficiently finds the minimum cost to paint houses with exactly the target number of neighborhoods. The memoized version improves performance by avoiding redundant calculations, making it suitable for larger inputs.

Updated on: 2026-03-26T14:01:05+05:30

564 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements