题目:
给你两个整数 m
和 n
,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices
,其中 prices[i] = [hi, wi, pricei]
表示你可以以 pricei
元的价格卖一块高为 hi
宽为 wi
的矩形木块。
每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:
- 沿垂直方向按高度 完全 切割木块,或
- 沿水平方向按宽度 完全 切割木块
在将一块木块切成若干小木块后,你可以根据 prices
卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。
请你返回切割一块大小为 m x n
的木块后,能得到的 最多 钱数。
注意你可以切割木块任意次。
思考:
1. 可能会用不同切割方式得到相同尺寸的木块 ----> 可能要多次计算同一个尺寸的木块的最大收益 ----> 重叠子问题(将已经计算过的尺寸的木块的收益记录下来避免重复计算)
2. 求得到的最多钱 ----> 求能得到最多钱的切割方法 ----> 计算每一种尺寸(不超过m*n大小)的木块的最优切割方法
因此,动态规划适用于这个问题:动态规划(Dynamic Programming,简称DP)通常用于优化问题的求解。它通常用于解决具有重叠子问题和最优子结构性质的问题。使用动态规划解决问题需要考虑两个关键步骤:确定状态和状态转移方程。
1.确定状态:
因为我们需要切割木块以获得最大收益,所以状态用木块的尺寸表示,即木块的高度和宽度。定义一个二维数组 dp
,其中 dp[i][j]
表示切割一个大小为 i x j
的木块后能得到的最大收益。
2.确定状态转移方程:
对于尺寸为(x,y)的木块,考虑三种情况:
① 如果数组 prices
中存在 (x,y,price)
这一三元组,表示可以以 price
的价格卖出一个高为 x
、宽为 y
的矩形木块,则状态转移方程为:
dp[x][y] = price
② 如果 x > 1
,那么可以沿水平方向将木块切割成两部分,它们的高分别是 i
和 x - i
,宽为 y
。状态转移方程为:
dp[x][y] = max(dp[i][y] + dp[x - i][y] for i in range(1, x))
③ 如果 y > 1
,那么可以沿垂直方向将木块切割成两部分,它们的宽分别是 j
和 y - j
,高为 x
。状态转移方程为:
dp[x][y] = max(dp[x][j] + dp[x][y - j] for j in range(1, y))
代码如下:
class Solution(object):
def sellingWood(self, m, n, prices):
"""
:type m: int
:type n: int
:type prices: List[List[int]]
:rtype: int
"""
# 构建哈希映射,键为木块的尺寸 (hi, wi),值为对应价格
price_map = {}
for hi, wi, price in prices:
price_map[(hi, wi)] = price
# 定义动态规划数组,dp[x][y]表示木块高为x、宽为y时的最大收益
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 遍历每个可能的木块尺寸
for x in range(1, m + 1):
for y in range(1, n + 1):
# 第一种情况:如果有对应的价格,直接取得最大收益
if (x, y) in price_map:
dp[x][y] = price_map[(x, y)]
# 第二种情况:沿水平方向切割木块
for i in range(1, x):
dp[x][y] = max(dp[x][y], dp[i][y] + dp[x - i][y])
# 第三种情况:沿垂直方向切割木块
for j in range(1, y):
dp[x][y] = max(dp[x][y], dp[x][j] + dp[x][y - j])
return dp[m][n]
运行通过:
动态规划早就忘干净了...感谢gpt帮我想起来 ^_^