298场 leetcode 周赛最后一题!虽然比赛的时候连题都没时间看,但赛后还是要好好复盘,谁让我菜呢。。
看完题目,脑袋里就蹦出来两种方法:dfs、dp,因为两者都用了递归的思想。
仔细想想 dp还是靠谱,解决相同子问题。
那如何去实现dp呢?这就难到我了 — —!思路不明确,于是浅看了一下答案:
思路:
容易不太能理解的点就是:
没看懂题意之前,个人理解为,按照木块的高度和宽度分两次切割一块下来。如此行为的话,与题目中 每次只进行一次切割后得到两块木块 相违背!
因此,题目的意思是,每次切割,不管竖着切还是横着切,都是一切到底,使得木块完完全全的分开!!!
按照“灵神”的解法,自己也梳理了一遍动规五部曲:
1.dp[i][j]:一般题目中是二维数组,设dp时也为二维数组,含义:切割高 i 宽 j 的木块后,能得到的最大钱数;
2.初始化:dp[i][j]=p[i][j], p[i][j] 表示高 i 宽 j 木块的钱数,需要通过prices进行转换。
3.递推公式:两种情况——横着切、竖着切
*****横着切:dp[i][j]=max(dp[i][j],dp[k][j]+dp[i-k][j]) // 切完选择最大值=max(切完卖,切完不卖)
*****竖着切:dp[i][j]=max(dp[i][j],dp[i][k]+dp[i][j-k]) // 切完选择最大值=max(切完卖,切完不卖)
4.循环顺序(从前往后)
5.打印数组
代码:
class Solution {
public:
long long sellingWood(int m, int n, vector<vector<int>>& prices) {
//dp[i][j] 含义 切割大小为 i*j 的木块后得到的最多钱数
vector<vector<long int>>dp(m+1,vector<long int>(n+1,0));
vector<vector<long int>>p(dp);
/* for(int i=0;i<prices.size();i++)
{
p[prices[i][0]][prices[i][1]]=prices[i][2];
}*/
for(auto&pr:prices)
{
p[pr[0]][pr[1]]=pr[2];
}
//递推公式:
//1. 切完就卖出;2. 横着切一刀,分成两个木块;3. 竖着切一刀,分成两个木块
//dp[i][j]=p[i][j];
//dp[i][j]=max(dp[i][j],dp[i-k][j]+dp[k][j]);//横着切高度为k的木块,分成两个更小的木块:max(卖,不卖)
//dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i][k]);//竖着切宽度为k的木块:max(卖,不卖)
//循环方向:从前往后
for(int i=1;i<m+1;i++)
{
for(int j=1;j<n+1;j++)
{
dp[i][j]=p[i][j];
for(int k=1;k<i;k++)dp[i][j]=max(dp[i][j],dp[i-k][j]+dp[k][j]);
for(int k=1;k<j;k++)dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i][k]);
}
}
return dp[m][n];
}
};