Skip to content

Commit b16ac71

Browse files
authoredMar 15, 2024
feat: add solutions to lc problem: No.2312 (doocs#2444)
No.2312.Selling Pieces of Wood
1 parent 588e981 commit b16ac71

File tree

12 files changed

+442
-223
lines changed

12 files changed

+442
-223
lines changed
 

‎solution/2300-2399/2312.Selling Pieces of Wood/README.md

+153-75
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,24 @@
7272

7373
### 方法一:记忆化搜索
7474

75+
我们先定义一个二维数组 $d$,其中 $d[i][j]$ 表示高为 $i$,宽为 $j$ 的木块的价格。初始时,我们遍历价格数组 $prices$,将每一块木块 $(h, w, p)$ 的价格 $p$ 存入 $d[h][w]$ 中,其余价格为 $0$。
76+
77+
然后我们设计一个函数 $dfs(h, w)$,表示对一块高为 $h$,宽为 $w$ 的木块切割后能得到的最多钱数。答案就是 $dfs(m, n)$。
78+
79+
函数 $dfs(h, w)$ 的执行过程如下:
80+
81+
- 如果 $(h, w)$ 已经被计算过了,直接返回答案。
82+
- 否则,我们先初始化答案为 $d[h][w]$,然后枚举切割的位置,分别计算切割后的两块木块能得到的最多钱数,取最大值即可。
83+
84+
时间复杂度 $(m \times n \times (m + n) + p)$,空间复杂度 $O(m \times n)$。其中 $p$ 表示价格数组的长度,而 $m$ 和 $n$ 分别表示木块的高和宽。
85+
7586
<!-- tabs:start -->
7687

7788
```python
7889
class Solution:
7990
def sellingWood(self, m: int, n: int, prices: List[List[int]]) -> int:
8091
@cache
81-
def dfs(h, w):
92+
def dfs(h: int, w: int) -> int:
8293
ans = d[h].get(w, 0)
8394
for i in range(1, h // 2 + 1):
8495
ans = max(ans, dfs(i, w) + dfs(h - i, w))
@@ -94,102 +105,137 @@ class Solution:
94105

95106
```java
96107
class Solution {
97-
private long[][] memo;
98108
private int[][] d;
109+
private Long[][] f;
99110

100111
public long sellingWood(int m, int n, int[][] prices) {
101112
d = new int[m + 1][n + 1];
102-
memo = new long[m + 1][n + 1];
103-
for (long[] e : memo) {
104-
Arrays.fill(e, -1);
105-
}
106-
for (int[] p : prices) {
113+
f = new Long[m + 1][n + 1];
114+
for (var p : prices) {
107115
d[p[0]][p[1]] = p[2];
108116
}
109117
return dfs(m, n);
110118
}
111119

112-
private long dfs(int m, int n) {
113-
if (memo[m][n] != -1) {
114-
return memo[m][n];
120+
private long dfs(int h, int w) {
121+
if (f[h][w] != null) {
122+
return f[h][w];
115123
}
116-
117-
long ans = d[m][n];
118-
for (int i = 1; i < m / 2 + 1; ++i) {
119-
ans = Math.max(ans, dfs(i, n) + dfs(m - i, n));
124+
long ans = d[h][w];
125+
for (int i = 1; i < h / 2 + 1; ++i) {
126+
ans = Math.max(ans, dfs(i, w) + dfs(h - i, w));
120127
}
121-
for (int i = 1; i < n / 2 + 1; ++i) {
122-
ans = Math.max(ans, dfs(m, i) + dfs(m, n - i));
128+
for (int i = 1; i < w / 2 + 1; ++i) {
129+
ans = Math.max(ans, dfs(h, i) + dfs(h, w - i));
123130
}
124-
memo[m][n] = ans;
125-
return ans;
131+
return f[h][w] = ans;
126132
}
127133
}
128134
```
129135

130136
```cpp
131-
using ll = long long;
132-
133137
class Solution {
134138
public:
135139
long long sellingWood(int m, int n, vector<vector<int>>& prices) {
136-
vector<vector<ll>> memo(m + 1, vector<ll>(n + 1, -1));
137-
vector<vector<int>> d(m + 1, vector<int>(n + 1));
138-
for (auto& p : prices) d[p[0]][p[1]] = p[2];
139-
return dfs(m, n, d, memo);
140-
}
141-
142-
ll dfs(int m, int n, vector<vector<int>>& d, vector<vector<ll>>& memo) {
143-
if (memo[m][n] != -1) return memo[m][n];
144-
ll ans = d[m][n];
145-
for (int i = 1; i < m / 2 + 1; ++i) ans = max(ans, dfs(i, n, d, memo) + dfs(m - i, n, d, memo));
146-
for (int i = 1; i < n / 2 + 1; ++i) ans = max(ans, dfs(m, i, d, memo) + dfs(m, n - i, d, memo));
147-
memo[m][n] = ans;
148-
return ans;
140+
using ll = long long;
141+
ll f[m + 1][n + 1];
142+
int d[m + 1][n + 1];
143+
memset(f, -1, sizeof(f));
144+
memset(d, 0, sizeof(d));
145+
for (auto& p : prices) {
146+
d[p[0]][p[1]] = p[2];
147+
}
148+
function<ll(int, int)> dfs = [&](int h, int w) -> ll {
149+
if (f[h][w] != -1) {
150+
return f[h][w];
151+
}
152+
ll ans = d[h][w];
153+
for (int i = 1; i < h / 2 + 1; ++i) {
154+
ans = max(ans, dfs(i, w) + dfs(h - i, w));
155+
}
156+
for (int i = 1; i < w / 2 + 1; ++i) {
157+
ans = max(ans, dfs(h, i) + dfs(h, w - i));
158+
}
159+
return f[h][w] = ans;
160+
};
161+
return dfs(m, n);
149162
}
150163
};
151164
```
152165
153166
```go
154167
func sellingWood(m int, n int, prices [][]int) int64 {
155-
memo := make([][]int, m+1)
168+
f := make([][]int64, m+1)
156169
d := make([][]int, m+1)
157-
for i := range memo {
158-
memo[i] = make([]int, n+1)
159-
d[i] = make([]int, n+1)
160-
for j := range memo[i] {
161-
memo[i][j] = -1
170+
for i := range f {
171+
f[i] = make([]int64, n+1)
172+
for j := range f[i] {
173+
f[i][j] = -1
162174
}
175+
d[i] = make([]int, n+1)
163176
}
164177
for _, p := range prices {
165178
d[p[0]][p[1]] = p[2]
166179
}
167-
var dfs func(int, int) int
168-
dfs = func(m, n int) int {
169-
if memo[m][n] != -1 {
170-
return memo[m][n]
180+
var dfs func(int, int) int64
181+
dfs = func(h, w int) int64 {
182+
if f[h][w] != -1 {
183+
return f[h][w]
171184
}
172-
ans := d[m][n]
173-
for i := 1; i < m/2+1; i++ {
174-
ans = max(ans, dfs(i, n)+dfs(m-i, n))
185+
ans := int64(d[h][w])
186+
for i := 1; i < h/2+1; i++ {
187+
ans = max(ans, dfs(i, w)+dfs(h-i, w))
175188
}
176-
for i := 1; i < n/2+1; i++ {
177-
ans = max(ans, dfs(m, i)+dfs(m, n-i))
189+
for i := 1; i < w/2+1; i++ {
190+
ans = max(ans, dfs(h, i)+dfs(h, w-i))
178191
}
179-
memo[m][n] = ans
192+
f[h][w] = ans
180193
return ans
181194
}
182-
return int64(dfs(m, n))
195+
return dfs(m, n)
196+
}
197+
```
198+
199+
```ts
200+
function sellingWood(m: number, n: number, prices: number[][]): number {
201+
const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1));
202+
const d: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
203+
for (const [h, w, p] of prices) {
204+
d[h][w] = p;
205+
}
206+
207+
const dfs = (h: number, w: number): number => {
208+
if (f[h][w] !== -1) {
209+
return f[h][w];
210+
}
211+
212+
let ans = d[h][w];
213+
for (let i = 1; i <= Math.floor(h / 2); i++) {
214+
ans = Math.max(ans, dfs(i, w) + dfs(h - i, w));
215+
}
216+
for (let i = 1; i <= Math.floor(w / 2); i++) {
217+
ans = Math.max(ans, dfs(h, i) + dfs(h, w - i));
218+
}
219+
return (f[h][w] = ans);
220+
};
221+
222+
return dfs(m, n);
183223
}
184224
```
185225

186226
<!-- tabs:end -->
187227

188228
### 方法二:动态规划
189229

190-
设 $dp[i][j]$ 表示对一块高为 $i$,宽为 $j$ 的木块切割后能得到的最多钱数。答案就是 $dp[m][n]$。
230+
我们可以将方法一的记忆化搜索转换为动态规划。
231+
232+
与方法一类似,我们定义一个二维数组 $d$,其中 $d[i][j]$ 表示高为 $i$,宽为 $j$ 的木块的价格。初始时,我们遍历价格数组 $prices$,将每一块木块 $(h, w, p)$ 的价格 $p$ 存入 $d[h][w]$ 中,其余价格为 $0$。
191233

192-
时间复杂度 $O(mn(m+n))$。
234+
然后,我们定义另一个二维数组 $f$,其中 $f[i][j]$ 表示对一块高为 $i$,宽为 $j$ 的木块切割后能得到的最多钱数。答案就是 $f[m][n]$。
235+
236+
考虑 $f[i][j]$ 如何转移,初始时 $f[i][j] = d[i][j]$。我们枚举切割的位置,分别计算切割后的两块木块能得到的最多钱数,取最大值即可。
237+
238+
时间复杂度 $O(m \times n \times (m + n) + p)$,空间复杂度 $O(m \times n)$。其中 $p$ 表示价格数组的长度,而 $m$ 和 $n$ 分别表示木块的高和宽。
193239

194240
相似题目:
195241

@@ -203,37 +249,37 @@ class Solution:
203249
d = defaultdict(dict)
204250
for h, w, p in prices:
205251
d[h][w] = p
206-
dp = [[0] * (n + 1) for _ in range(m + 1)]
252+
f = [[0] * (n + 1) for _ in range(m + 1)]
207253
for i in range(1, m + 1):
208254
for j in range(1, n + 1):
209-
dp[i][j] = d[i].get(j, 0)
255+
f[i][j] = d[i].get(j, 0)
210256
for k in range(1, i):
211-
dp[i][j] = max(dp[i][j], dp[k][j] + dp[i - k][j])
257+
f[i][j] = max(f[i][j], f[k][j] + f[i - k][j])
212258
for k in range(1, j):
213-
dp[i][j] = max(dp[i][j], dp[i][k] + dp[i][j - k])
214-
return dp[-1][-1]
259+
f[i][j] = max(f[i][j], f[i][k] + f[i][j - k])
260+
return f[m][n]
215261
```
216262

217263
```java
218264
class Solution {
219265
public long sellingWood(int m, int n, int[][] prices) {
220266
int[][] d = new int[m + 1][n + 1];
221-
long[][] dp = new long[m + 1][n + 1];
267+
long[][] f = new long[m + 1][n + 1];
222268
for (int[] p : prices) {
223269
d[p[0]][p[1]] = p[2];
224270
}
225271
for (int i = 1; i <= m; ++i) {
226272
for (int j = 1; j <= n; ++j) {
227-
dp[i][j] = d[i][j];
273+
f[i][j] = d[i][j];
228274
for (int k = 1; k < i; ++k) {
229-
dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]);
275+
f[i][j] = Math.max(f[i][j], f[k][j] + f[i - k][j]);
230276
}
231277
for (int k = 1; k < j; ++k) {
232-
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]);
278+
f[i][j] = Math.max(f[i][j], f[i][k] + f[i][j - k]);
233279
}
234280
}
235281
}
236-
return dp[m][n];
282+
return f[m][n];
237283
}
238284
}
239285
```
@@ -242,44 +288,76 @@ class Solution {
242288
class Solution {
243289
public:
244290
long long sellingWood(int m, int n, vector<vector<int>>& prices) {
245-
vector<vector<int>> d(m + 1, vector<int>(n + 1));
246-
vector<vector<long long>> dp(m + 1, vector<long long>(n + 1));
247-
for (auto& p : prices) d[p[0]][p[1]] = p[2];
291+
long long f[m + 1][n + 1];
292+
int d[m + 1][n + 1];
293+
memset(f, -1, sizeof(f));
294+
memset(d, 0, sizeof(d));
295+
for (auto& p : prices) {
296+
d[p[0]][p[1]] = p[2];
297+
}
248298
for (int i = 1; i <= m; ++i) {
249299
for (int j = 1; j <= n; ++j) {
250-
dp[i][j] = d[i][j];
251-
for (int k = 1; k < i; ++k) dp[i][j] = max(dp[i][j], dp[k][j] + dp[i - k][j]);
252-
for (int k = 1; k < j; ++k) dp[i][j] = max(dp[i][j], dp[i][k] + dp[i][j - k]);
300+
f[i][j] = d[i][j];
301+
for (int k = 1; k < i; ++k) {
302+
f[i][j] = max(f[i][j], f[k][j] + f[i - k][j]);
303+
}
304+
for (int k = 1; k < j; ++k) {
305+
f[i][j] = max(f[i][j], f[i][k] + f[i][j - k]);
306+
}
253307
}
254308
}
255-
return dp[m][n];
309+
return f[m][n];
256310
}
257311
};
258312
```
259313
260314
```go
261315
func sellingWood(m int, n int, prices [][]int) int64 {
262316
d := make([][]int, m+1)
263-
dp := make([][]int, m+1)
317+
f := make([][]int64, m+1)
264318
for i := range d {
265319
d[i] = make([]int, n+1)
266-
dp[i] = make([]int, n+1)
320+
f[i] = make([]int64, n+1)
267321
}
268322
for _, p := range prices {
269323
d[p[0]][p[1]] = p[2]
270324
}
271325
for i := 1; i <= m; i++ {
272326
for j := 1; j <= n; j++ {
273-
dp[i][j] = d[i][j]
327+
f[i][j] = int64(d[i][j])
274328
for k := 1; k < i; k++ {
275-
dp[i][j] = max(dp[i][j], dp[k][j]+dp[i-k][j])
329+
f[i][j] = max(f[i][j], f[k][j]+f[i-k][j])
276330
}
277331
for k := 1; k < j; k++ {
278-
dp[i][j] = max(dp[i][j], dp[i][k]+dp[i][j-k])
332+
f[i][j] = max(f[i][j], f[i][k]+f[i][j-k])
279333
}
280334
}
281335
}
282-
return int64(dp[m][n])
336+
return f[m][n]
337+
}
338+
```
339+
340+
```ts
341+
function sellingWood(m: number, n: number, prices: number[][]): number {
342+
const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
343+
const d: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
344+
for (const [h, w, p] of prices) {
345+
d[h][w] = p;
346+
}
347+
348+
for (let i = 1; i <= m; i++) {
349+
for (let j = 1; j <= n; j++) {
350+
f[i][j] = d[i][j];
351+
for (let k = 1; k < i; k++) {
352+
f[i][j] = Math.max(f[i][j], f[k][j] + f[i - k][j]);
353+
}
354+
for (let k = 1; k < j; k++) {
355+
f[i][j] = Math.max(f[i][j], f[i][k] + f[i][j - k]);
356+
}
357+
}
358+
}
359+
360+
return f[m][n];
283361
}
284362
```
285363

0 commit comments

Comments
 (0)