class Solution:
def sellingWood(self, m: int, n: int, prices: List[List[int]]) -> int:
dp = [[0] * (n + 1) for _ in range(m + 1)]
price_map = {(h, w): p for h, w, p in prices}
for i in range(1, m + 1):
for j in range(1, n + 1):
# Option 1: sell as whole, if possible
dp[i][j] = price_map.get((i, j), 0)
# Option 2: cut horizontally
for k in range(1, i // 1):
dp[i][j] = max(dp[i][j], dp[k][j] + dp[i - k][j])
# Option 3: cut vertically
for k in range(1, j // 1):
dp[i][j] = max(dp[i][j], dp[i][k] + dp[i][j - k])
return dp[m][n]
class Solution {
public:
int sellingWood(int m, int n, vector<vector<int>>& prices) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
unordered_map<int, unordered_map<int, int>> priceMap;
for (auto& p : prices) {
priceMap[p[0]][p[1]] = p[2];
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
dp[i][j] = priceMap[i][j];
for (int k = 1; k < i; ++k) {
dp[i][j] = max(dp[i][j], dp[k][j] + dp[i - k][j]);
}
for (int k = 1; k < j; ++k) {
dp[i][j] = max(dp[i][j], dp[i][k] + dp[i][j - k]);
}
}
}
return dp[m][n];
}
};
class Solution {
public int sellingWood(int m, int n, int[][] prices) {
int[][] dp = new int[m + 1][n + 1];
Map<String, Integer> priceMap = new HashMap<>();
for (int[] p : prices) {
priceMap.put(p[0] + "," + p[1], p[2]);
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = priceMap.getOrDefault(i + "," + j, 0);
for (int k = 1; k < i; k++) {
dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]);
}
for (int k = 1; k < j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]);
}
}
}
return dp[m][n];
}
}
var sellingWood = function(m, n, prices) {
const dp = Array.from({length: m + 1}, () => Array(n + 1).fill(0));
const priceMap = new Map();
for (const [h, w, p] of prices) {
priceMap.set(h + ',' + w, p);
}
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] = priceMap.get(i + ',' + j) || 0;
for (let k = 1; k < i; k++) {
dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]);
}
for (let k = 1; k < j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]);
}
}
}
return dp[m][n];
};
m
by n
. You can sell certain sub-rectangles of this wood for a given price, specified in the list prices
. Each element of prices
is a triple [height, width, price]
, indicating that a piece of wood with those dimensions can be sold for that price. You can cut the wood into any number of pieces by making horizontal or vertical cuts, and you may sell any number of pieces (including multiple of the same size, if you can cut them out). Your goal is to maximize the total profit by cutting and selling the wood.
prices
.prices
.m
and n
because the number of ways to cut grows exponentially.
A better approach is to use dynamic programming. The key insight is that the optimal way to cut and sell a piece of wood of size i x j
depends only on the optimal ways to cut and sell its smaller sub-rectangles. By storing the results for each sub-rectangle, we avoid recalculating the same values repeatedly.
This is a classic "optimal substructure" and "overlapping subproblems" scenario, which are ideal for dynamic programming.
dp
, where dp[i][j]
represents the maximum profit obtainable from a rectangle of size i x j
.
price_map
) from the prices
list for quick lookup of the price for each sellable size.dp[i][j]
to 0 for all i
and j
.i
(from 1 to m
) and widths j
(from 1 to n
).(i, j)
is a sellable size (exists in price_map
), set dp[i][j]
to its sell price.k
, where 1 ≤ k < i
), and update dp[i][j]
as the maximum of its current value and dp[k][j] + dp[i-k][j]
.k
, where 1 ≤ k < j
), and update dp[i][j]
as the maximum of its current value and dp[i][k] + dp[i][j-k]
.dp[m][n]
, the maximum profit for the original piece.
m = 3
, n = 5
, and prices = [[3,5,10],[1,1,2],[2,2,7],[1,2,3]]
.
dp
for all smaller rectangles:
1x1
, price is 2.2x2
, price is 7.1x2
, price is 3.dp[2][2]
could be sold whole (7), or cut into two 1x2
pieces (each worth 3), for a total of 6. So we keep 7.dp[3][5]
, we check all possible horizontal and vertical cuts. For instance, cutting horizontally at 1 gives dp[1][5] + dp[2][5]
. We compute these recursively using previously filled values.O(mn)
subproblems (dp[i][j]
for each i
and j
).O(m + n)
possible cuts (all possible horizontal and vertical cuts).O(mn(m + n))
.O(mn)
for the dp
table.dp[i][j]
for each rectangle size).