递归写法
类和方法
Solution
类:包含问题的解决方案。sellingWood
方法:解决问题的入口点,接受木材尺寸 (m
,n
) 和不同尺寸的木材价格数组 (prices
)。
变量
dp
(动态规划表):一个二维数组,用于存储从尺寸为i
乘以j
的木材中可以获得的最大利润。初始化为m+1
行n+1
列。vis
(访问表):一个二维布尔数组,用于跟踪给定尺寸的木材的最大利润是否已经计算过。这有助于避免重复计算。max
:一个变量,用于跟踪计算过程中找到的最大利润。
逻辑
-
初始化:
dp
数组根据prices
数组中给定的尺寸和价格填充。vis
数组初始化为false
,表示最初没有任何单元格的最优值被计算过。
-
sellingWood
方法:- 通过调用
f(m, n, m, n)
开始动态规划过程,旨在找到尺寸为m
乘以n
的木材的最大利润。 - 返回最大利润,确保其不小于最初设置的
max
(即Long.MIN_VALUE
)。
- 通过调用
-
f
(递归函数):- 基本情况:如果当前木块的尺寸减小到0(
i
或j
),意味着无法获得利润,因此返回0。 - 递归步骤:通过出售原木(如果
dp
中定义了价格)或切割并出售部分来计算当前尺寸(i
,j
)的最大利润。这涉及:- 横向和纵向切割,考虑将木块切成两个较小部分的所有可能方式。它递归计算每个较小部分的最大利润并加在一起。
- 用当前尺寸的木块的最大利润更新
dp
表。 - 在
vis
数组中标记当前尺寸的木块为已访问。 - 如果找到新的最大利润,则更新
max
变量。
- 基本情况:如果当前木块的尺寸减小到0(
结论
这段代码使用动态规划和记忆化(在 dp
中缓存中间结果,并使用 vis
跟踪已计算的状态)来有效解决切割和销售木材以实现最大可能利润的问题。递归函数 f
探索将木材切成较小部分的所有可能方式,确保实现最大可能的利润。
LeetCode2024年3月14日每日一题(2789. 合并后数组中的最大元素)
class Solution {
public static long[][]dp;
public static boolean [][]vis;
public long max=Long.MIN_VALUE;
public long sellingWood(int m, int n, int[][] prices) {
dp=new long[m+1][n+1];
vis=new boolean[m+1][n+1];
for(int[]a:prices){
dp[a[0]][a[1]]=a[2];
}
for(boolean[]b:vis){
Arrays.fill(b,false);
}
return Math.max(max,f(m,n,m,n));
}
public long f(int i,int j,int m,int n){
if(i==0||j==0){
return 0;
}
long ans = dp[i][j];
for (int k = 1; k <=j/2 ; k++) {
ans=Math.max((!vis[i][j-k]?f(i,j-k,m,n):dp[i][j-k])+(!vis[i][k]?f(i,k,m,n):dp[i][k]),ans);
}
for (int k = 1; k <=i/2 ; k++) {
ans=Math.max((!vis[i-k][j]?f(i-k,j,m,n):dp[i-k][j])+(!vis[k][j]?f(k,j,m,n):dp[k][j]),ans);
}
dp[i][j]=ans;
vis[i][j]=true;
max=Math.max(max,ans);
return ans;
}
}
循环写法
class Solution {
public long sellingWood(int m, int n, int[][] prices) {
long ans=Long.MIN_VALUE;
long[][]dp=new long[m+1][n+1];
for(int[]arr:prices){
dp[arr[0]][arr[1]]=arr[2];
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <=n ; j++) {
for(int k=1;k<=j/2;k++){
dp[i][j]=Math.max(dp[i][k]+dp[i][j-k],dp[i][j]);
}
for(int k=1;k<=i/2;k++){
dp[i][j]=Math.max(dp[i-k][j]+dp[k][j],dp[i][j]);
}
ans=Math.max(ans,dp[i][j]);
}
}
return ans;
}
}
方法和逻辑
sellingWood
方法:该方法是算法的主入口,接收木材的初始尺寸m
和n
(长度和宽度),以及一个表示不同尺寸木材的价格的二维数组prices
。
变量
ans
:用于存储和更新找到的最大收益值,初始值设为Long.MIN_VALUE
,确保任何正的收益都会被考虑。dp
(动态规划表):一个(m+1)x(n+1)
的二维数组,用于存储达到每个可能的尺寸(i, j)
时能获得的最大收益。
初始化
- 价格表初始化:遍历
prices
数组,将每个尺寸对应的价格填入dp
表相应的位置。
动态规划过程
- 遍历所有可能的尺寸:通过两层循环遍历木材的所有可能长度
i
和宽度j
。 - 横向和纵向切割:对于每个尺寸
(i, j)
,内部的两个循环分别尝试所有可能的横向切割和纵向切割方式。对于横向切割,尝试在第k
位置切割;对于纵向切割,尝试在第k
位置切割。 - 更新
dp
表:通过比较当前的dp[i][j]
值和通过切割得到的两部分的收益之和,更新dp[i][j]
为这两个值中的较大值。 - 更新最大收益
ans
:在每次更新dp[i][j]
后,比较并更新全局最大收益ans
。
返回值
- 方法最后返回
ans
,即通过销售给定尺寸的木材所能获得的最大收益。