You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.6 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_06_3_week;
// 给你两个整数 m 和 n 分别表示一块矩形木块的高和宽。
// 同时给你一个二维整数数组 prices 其中 prices[i] = [hi, wi, pricei] 
// 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。
// 每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:
// 沿垂直方向按高度 完全 切割木块,或
// 沿水平方向按宽度 完全 切割木块
// 在将一块木块切成若干小木块后,你可以根据 prices 卖木块。
// 你可以卖多块同样尺寸的木块。
// 你不需要将所有小木块都卖出去。
// 你 不能 旋转切好后木块的高和宽。
// 请你返回切割一块大小为 m x n 的木块后,能得到的 最多 钱数。
// 注意你可以切割木块任意次。
// 测试链接 : https://leetcode.cn/problems/selling-pieces-of-wood/
public class Code02_SellingPiecesOfWood {
// [1, 3,10元]
// [3, 5, 7元]
// [2, 6, 5元]
// 100 * 100
// values -> 100 * 100
// values[1][3] = 10
// values[3][5] = 7
// values[2][6] = 5
// values[5][5] = 0元
// m * n这块木板只能水平分割、垂直分割的情况下能获得的最大总钱数是多少
public static int zuo(int m, int n, int[][] values) {
// base case
if (m == 0 || n == 0) {
return 0;
}
// m > 0 & n > 0木块还有面积
// 普遍分析
// 可能性1一刀也不切
int ans = values[m][n]; // 0元 >0元
// 接下来的一系列可能性:水平方向上,都去试一试
for (int split = 1; split < m; split++) {
int up = zuo(split, n, values);
int down = zuo(m - split, n, values);
ans = Math.max(ans, up + down);
}
// 垂直方向上,都去试一试
for (int split = 1; split < n; split++) {
int left = zuo(m, split, values);
int right = zuo(m, n - split, values);
ans = Math.max(ans, left + right);
}
return ans;
}
// 递归尝试版本
public static long sellingWood1(int m, int n, int[][] prices) {
// 单一报价
long[][] values = new long[m + 1][n + 1];
// 2 * 7 10元
// 2 * 7 100元
for (int[] p : prices) {
values[p[0]][p[1]] = Math.max(values[p[0]][p[1]], p[2]);
}
return f1(m, n, values);
}
public static long f1(int m, int n, long[][] values) {
if (m == 0 || n == 0) {
return 0;
}
long ans = values[m][n];
for (int split = 1; split < m; split++) {
ans = Math.max(ans, f1(split, n, values) + f1(m - split, n, values));
}
for (int split = 1; split < n; split++) {
ans = Math.max(ans, f1(m, split, values) + f1(m, n - split, values));
}
return ans;
}
// 递归版本 + 记忆化搜索
public static long sellingWood2(int m, int n, int[][] prices) {
long[][] values = new long[m + 1][n + 1];
for (int[] p : prices) {
values[p[0]][p[1]] = Math.max(values[p[0]][p[1]], p[2]);
}
long[][] dp = new long[m + 1][n + 1];
// dp[10][20] :没算过,-1
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = -1;
}
}
return f2(m, n, values, dp);
}
public static long f2(int m, int n, long[][] values, long[][] dp) {
if (m == 0 || n == 0) {
return 0;
}
if (dp[m][n] != -1) {
return dp[m][n];
}
long ans = values[m][n];
for (int split = 1; split < m; split++) {
ans = Math.max(ans, f2(split, n, values, dp) + f2(m - split, n, values, dp));
}
for (int split = 1; split < n; split++) {
ans = Math.max(ans, f2(m, split, values, dp) + f2(m, n - split, values, dp));
}
dp[m][n] = ans;
return ans;
}
// 严格位置依赖的动态规划版本 + 优化
// 优化1 : 递归的形式,改成迭代形式,课上讲了
// 优化2 : prices中的单块收益直接填入dp表即可如果有更好的分割方案更新掉
// 优化3 : 分割只需要枚举一半即可
public static long sellingWood3(int m, int n, int[][] prices) {
// dp表
long[][] dp = new long[m + 1][n + 1];
for (int[] p : prices) {
// {3, 5, 100}
// 0 1 2
// dp[3][5] = 100
dp[p[0]][p[1]] = p[2];
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 垂直分割
// i * j = 100 * 100
// dp[100][1] + dp[100][99]
// dp[100][2] + dp[100][98]
// ..
for (int k = 1; k <= (j >> 1); k++) {
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]);
}
// 水平分割
// 100 * 100
// 1) 1 * 100 + 99 * 100
// 1) 2 * 100 + 98 * 100
// i * j
// 1) 1 * j + (i - 1) * i;
// 2) 2 * j + (i - 2) * j;
// k) k * j + (i - k) * j;
for (int k = 1; k <= (i >> 1); k++) {
dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]);
}
}
}
return dp[m][n];
}
}