72
72
73
73
### 方法一:记忆化搜索
74
74
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
+
75
86
<!-- tabs:start -->
76
87
77
88
``` python
78
89
class Solution :
79
90
def sellingWood (self , m : int , n : int , prices : List[List[int ]]) -> int :
80
91
@cache
81
- def dfs (h , w ) :
92
+ def dfs (h : int , w : int ) -> int :
82
93
ans = d[h].get(w, 0 )
83
94
for i in range (1 , h // 2 + 1 ):
84
95
ans = max (ans, dfs(i, w) + dfs(h - i, w))
@@ -94,102 +105,137 @@ class Solution:
94
105
95
106
``` java
96
107
class Solution {
97
- private long [][] memo;
98
108
private int [][] d;
109
+ private Long [][] f;
99
110
100
111
public long sellingWood (int m , int n , int [][] prices ) {
101
112
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) {
107
115
d[p[0 ]][p[1 ]] = p[2 ];
108
116
}
109
117
return dfs(m, n);
110
118
}
111
119
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 ];
115
123
}
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));
120
127
}
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));
123
130
}
124
- memo[m][n] = ans;
125
- return ans;
131
+ return f[h][w] = ans;
126
132
}
127
133
}
128
134
```
129
135
130
136
``` cpp
131
- using ll = long long ;
132
-
133
137
class Solution {
134
138
public:
135
139
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);
149
162
}
150
163
};
151
164
```
152
165
153
166
```go
154
167
func sellingWood(m int, n int, prices [][]int) int64 {
155
- memo := make ([][]int , m+1 )
168
+ f := make([][]int64 , m+1)
156
169
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
162
174
}
175
+ d[i] = make([]int, n+1)
163
176
}
164
177
for _, p := range prices {
165
178
d[p[0]][p[1]] = p[2]
166
179
}
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 ]
171
184
}
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 ))
175
188
}
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))
178
191
}
179
- memo[m][n ] = ans
192
+ f[h][w ] = ans
180
193
return ans
181
194
}
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 );
183
223
}
184
224
```
185
225
186
226
<!-- tabs: end -->
187
227
188
228
### 方法二:动态规划
189
229
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$。
191
233
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$ 分别表示木块的高和宽。
193
239
194
240
相似题目:
195
241
@@ -203,37 +249,37 @@ class Solution:
203
249
d = defaultdict(dict )
204
250
for h, w, p in prices:
205
251
d[h][w] = p
206
- dp = [[0 ] * (n + 1 ) for _ in range (m + 1 )]
252
+ f = [[0 ] * (n + 1 ) for _ in range (m + 1 )]
207
253
for i in range (1 , m + 1 ):
208
254
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 )
210
256
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])
212
258
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 ]
215
261
```
216
262
217
263
``` java
218
264
class Solution {
219
265
public long sellingWood (int m , int n , int [][] prices ) {
220
266
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 ];
222
268
for (int [] p : prices) {
223
269
d[p[0 ]][p[1 ]] = p[2 ];
224
270
}
225
271
for (int i = 1 ; i <= m; ++ i) {
226
272
for (int j = 1 ; j <= n; ++ j) {
227
- dp [i][j] = d[i][j];
273
+ f [i][j] = d[i][j];
228
274
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]);
230
276
}
231
277
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]);
233
279
}
234
280
}
235
281
}
236
- return dp [m][n];
282
+ return f [m][n];
237
283
}
238
284
}
239
285
```
@@ -242,44 +288,76 @@ class Solution {
242
288
class Solution {
243
289
public:
244
290
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
+ }
248
298
for (int i = 1; i <= m; ++i) {
249
299
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
+ }
253
307
}
254
308
}
255
- return dp [ m] [ n ] ;
309
+ return f [ m] [ n ] ;
256
310
}
257
311
};
258
312
```
259
313
260
314
```go
261
315
func sellingWood(m int, n int, prices [][]int) int64 {
262
316
d := make([][]int, m+1)
263
- dp := make([][]int , m+1)
317
+ f := make([][]int64 , m+1)
264
318
for i := range d {
265
319
d[i] = make([]int, n+1)
266
- dp [i] = make([]int , n+1)
320
+ f [i] = make([]int64 , n+1)
267
321
}
268
322
for _, p := range prices {
269
323
d[p[0]][p[1]] = p[2]
270
324
}
271
325
for i := 1; i <= m; i++ {
272
326
for j := 1; j <= n; j++ {
273
- dp [i][j] = d[i][j]
327
+ f [i][j] = int64( d[i][j])
274
328
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])
276
330
}
277
331
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])
279
333
}
280
334
}
281
335
}
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 ];
283
361
}
284
362
```
285
363
0 commit comments