一、题目
1、题目描述
给你两个整数
m
和n
,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组prices
,其中prices[i] = [hi, wi, pricei]
表示你可以以pricei
元的价格卖一块高为hi
宽为wi
的矩形木块。每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:
- 沿垂直方向按高度 完全 切割木块,或
- 沿水平方向按宽度 完全 切割木块
在将一块木块切成若干小木块后,你可以根据
prices
卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。请你返回切割一块大小为
m x n
的木块后,能得到的 最多 钱数。注意你可以切割木块任意次。
2、接口描述
class Solution {
public:
long long sellingWood(int m, int n, vector<vector<int>>& prices) {
}
};
3、原题链接
二、解题报告
1、思路分析
关于区间dp,详见:区间DP详解,思路分析,OJ详解-CSDN博客
定义f[l][r]为l × r的矩形的最大收益
那么横切纵切都会有若干子状态,分别由两种切法的子状态转移即可
O(n)转移,O(n^2)状态数,总体O(n^3)的区间dp
2、复杂度
时间复杂度: O(n^3)空间复杂度:O(n^2)
3、代码详解
class Solution {
public:
long long f[205][205];
long long sellingWood(int m, int n, vector<vector<int>>& prices) {
unordered_map<int, int> mp;
for(auto& p : prices)
mp[p[0] << 8 | p[1]] = max(p[2], mp[p[0] << 8 | p[1]]);
memset(f, -1, sizeof f);
function<long long(int, int)> dfs = [&](int l, int r)->long long{
if(l <= 0 || r <= 0) return 0;
if(~f[l][r]) return f[l][r];
long long& res = f[l][r] = 0;
if(mp.count(l << 8 | r)) res = mp[l << 8 | r];
for(int i = 1; i < l; i++)
res = max(res, dfs(i, r) + dfs(l - i, r));
for(int i = 1; i < r; i++)
res = max(res, dfs(l, i) + dfs(l, r - i));
return res;
};
return dfs(m, n);
}
};