2025-08-01:粉刷房子Ⅳ。用go语言,给定一个偶数个房屋排列在一条直线上,和一个大小为 n x 3 的二维数组 cost,其中 cost[i][j] 表示给第 i 个房屋涂第 j + 1 种颜色的花费。
房屋的涂色需要满足两个条件才算“美观”:
请计算出符合这些条件的涂色方案中,涂色总花费最低的方案所对应的最低开销。
2 <= n <= 100000。
n 是偶数。
cost.length == n。
cost[i].length == 3。
0 <= cost[i][j] <= 100000。
输入: n = 4, cost = [[3,5,7],[6,2,9],[4,8,1],[7,3,5]]。
输出: 9。
解释:
最佳涂色顺序为 [1, 2, 3, 2],对应的成本为 [3, 2, 1, 3]。满足以下条件:
不存在涂成相同颜色的相邻房屋。
位置 0 和 3 的房屋(等距于两端)涂成不同的颜色 (1 != 2)。
位置 1 和 2 的房屋(等距于两端)涂成不同的颜色 (2 != 3)。
使房屋看起来漂亮的最低涂色成本为 3 + 2 + 1 + 3 = 9。
题目来自力扣3429。
由于房屋是对称的,我们可以将房屋分成对称的两部分来处理。对于第 i 个房屋和第 n-1-i 个房屋,我们需要确保它们的颜色不同,同时相邻房屋的颜色也不同。
我们可以使用动态规划来解决这个问题。定义 f[i][j][k]
表示处理到第 i 对对称房屋时,前一个房屋的颜色为 j,当前对称对中第一个房屋的颜色为 k 时的最小总花费。
对于每一对对称的房屋(第 i 个和第 n-1-i 个),我们需要选择它们的颜色:
因此,对于每一对房屋,我们需要枚举前一个房屋的颜色和当前对称对中第一个房屋的颜色,然后选择满足约束的颜色组合,并更新动态规划状态。
初始时,没有前一个房屋,因此可以认为前一个房屋的颜色是“虚拟”的(即可以任意选择,但需要在后续处理中确保约束)。
处理完所有对称对后,我们需要在所有可能的最后状态中选择最小的总花费。
对于输入 n = 4
, cost = [[3,5,7],[6,2,9],[4,8,1],[7,3,5]]
:
实际最优解是:
原始动态规划可能没有正确处理相邻约束和对称约束的结合。可能需要更精细的状态设计或优化。
.
package main
import (
"fmt"
"math"
"slices"
)
func minCost(n int, cost [][]int)int64 {
f := make([][3][3]int, n/2+1)
for i, row := range cost[:n/2] {
row2 := cost[n-1-i]
for preJ := range3 {
for preK := range3 {
res := math.MaxInt
for j, c1 := range row {
if j == preJ {
continue
}
for k, c2 := range row2 {
if k != preK && k != j {
res = min(res, f[i][j][k]+c1+c2)
}
}
}
f[i+1][preJ][preK] = res
}
}
}
// 枚举所有初始颜色,取最小值
res := math.MaxInt
for _, row := range f[n/2] {
res = min(res, slices.Min(row[:]))
}
returnint64(res)
}
func main() {
n := 4
cost := [][]int{{3, 5, 7}, {6, 2, 9}, {4, 8, 1}, {7, 3, 5}}
result := minCost(n, cost)
fmt.Println(result)
}
.
# -*-coding:utf-8-*-
import math
def min_cost(n, cost):
# f[i][j][k] 表示涂第i组(对称位置的两间房)时,
# 左边房屋颜色为 j,右边房屋颜色为 k 的最小花费
f = [[[math.inf]*3for _ in range(3)] for _ in range(n//2+1)]
# 初始化 f[0],第一组前没有房屋,花费为0
for j in range(3):
for k in range(3):
f[0][j][k] = 0
for i in range(n//2):
row_left = cost[i]
row_right = cost[n - 1 - i]
for preJ in range(3):
for preK in range(3):
res = math.inf
for j, c1 in enumerate(row_left):
if j == preJ:
continue
for k, c2 in enumerate(row_right):
if k != preK and k != j:
cand = f[i][j][k] + c1 + c2
if cand < res:
res = cand
f[i+1][preJ][preK] = res
# 找出 f[n/2] 中的最小值
res = math.inf
for row in f[n//2]:
res = min(res, min(row))
return res
if __name__ == '__main__':
n = 4
cost = [
[3, 5, 7],
[6, 2, 9],
[4, 8, 1],
[7, 3, 5]
]
print(min_cost(n, cost))