给你两个整数 m
和 n
,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices
,其中 prices[i] = [hi, wi, pricei]
表示你可以以 pricei
元的价格卖一块高为 hi
宽为 wi
的矩形木块。
每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:
- 沿垂直方向按高度 完全 切割木块,或
- 沿水平方向按宽度 完全 切割木块
在将一块木块切成若干小木块后,你可以根据 prices
卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。
请你返回切割一块大小为 m x n
的木块后,能得到的 最多 钱数。
注意你可以切割木块任意次。
示例 1:
输入:m = 3, n = 5, prices = [[1,4,2],[2,2,7],[2,1,3]] 输出:19 解释:上图展示了一个可行的方案。包括: - 2 块 2 x 2 的小木块,售出 2 * 7 = 14 元。 - 1 块 2 x 1 的小木块,售出 1 * 3 = 3 元。 - 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。 总共售出 14 + 3 + 2 = 19 元。 19 元是最多能得到的钱数。
示例 2:
输入:m = 4, n = 6, prices = [[3,2,10],[1,4,2],[4,1,3]] 输出:32 解释:上图展示了一个可行的方案。包括: - 3 块 3 x 2 的小木块,售出 3 * 10 = 30 元。 - 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。 总共售出 30 + 2 = 32 元。 32 元是最多能得到的钱数。 注意我们不能旋转 1 x 4 的木块来得到 4 x 1 的木块。
提示:
1 <= m, n <= 200
1 <= prices.length <= 2 * 104
prices[i].length == 3
1 <= hi <= m
1 <= wi <= n
1 <= pricei <= 106
- 所有
(hi, wi)
互不相同 。
//
// Created by py on 24-3-15.
//
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <deque>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
class Solution {
public:
/*
* 本题说实话并没有很明白,我看着不怎么符合数学原理,先写会注释理解理解
* ( 先行说明:砍下来的木块长宽不能调换( 真不符合实际 ))
* 一开始先创建好dp表( f数组 )二维的?为什么是二维的????
* *************************************************
* 把prices遍历一遍,并且把刚刚好这么大的木块直接扔进去至(疑问,不一定会固定这个值,状态转移应该会修改)
* 继续看看,原来要启动填表了
*
* 从小下标的开始遍历,横着砍,竖着砍,多多帮忙砍一砍( bushi )
* 砍的时候找找哪个姿势砍的比较大( 遍历寻找砍那一刀的下标 ,其中有重复砍法 故 / 2,详解请看下边具体代码 )
* 难的就这里了,为什么多多砍一刀方法就可以寻找到最大 price 呢 ?
* 星号中间是本人思考历程,不想看直接跳过
* ********************************************
* 原本我作题的时候就感受到一股强烈的 dp 气味
* 我一开始,直接建立二维表( 为啥,因为这木块是二维的 笑死)
* 从递归的叶子节点思考,要求 m,n 大的木块
* 这不得从 1,1 叶子启动 ?
* 我就开始启动填表状态了
* 之后就填,填填就填不动了
* **********************************************
* 看了一眼题解
* 切割方法,真奇怪了
* 填了一会用这方法,发现原来我是🥬批
* 这都没想到,建议填一填( 填一填 ,填一填)
* 本题属于记忆化搜索,因为有三个可能:1.假如prices数组刚刚好就有就有的话,属于一种可能
* 2.横着的维度中( 看清楚是横着的维度,竖着的就不管先了,因为是另一种可能 )
* 循环中就是 i ,dp得看看dp[i-n][j] i - n >= 1( 为啥是 1 ,因为长宽没有0 )
* 当初假如方块是 i-n ,j中最大的price是多少,现在在加 i-n 多上 n
* 例如原本是 2,4 的木块已经得到最大的prices了
* 那么现在我要求 5,4 的木块实际上就是求 3,4 木块的最大prices
* 3,4 的木块是否是得看 2,4 的木块 和 1,4 的木块怎么买得最大
* 这样递归的话就可以解释为什么是从小的下标开始了
* 当然 5,4 木块的横着维度找最大值有两种组合:1,4木块和4,4木块
* 2,4木块和3,4木块
* 求解这些个木块就可以得到横着维度中最大值
* 可能有点奇怪,这样似乎是不能遍历所有可能一样
* (但是我们要清楚,我们去求解1,4等木块的时候,就已经按竖着的维度遍历过1,1木块,1,2木块了)
* (所以说这种1,4木块最大prices已经隐含过更小的木块的遍历了)
* 3.竖着的维度和横着是一样的思路
* 原本这个就是二维的木块了,两个维度和起来就可以遍历所有可能性了
* 假如是个三维木块的题呢,那肯定是x,y,z三个维度,遍历所有可能就可以得到了
*
* */
long long sellingWood(int m, int n, vector<vector<int>> prices) {
//这里的 +1 操作应该是懒得后边 -1 ,因为宽和高是没有 0 这种说法的
vector<vector<long long>> dp(m + 1, vector<long long>(n + 1));
// 先将dp表(dp 表)把所有的可能 prices数组 扔进去(分割的时候刚刚好这么大可以买这么多)
for (auto &p: prices) {
// 遍历所有的prices
dp[p[0]][p[1]] = p[2];
}
/*
* 启动填表模式
* */
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
/*
* 竖着切,对的就是物理的 竖着 | 这样把木块砍一刀
* 这里有一个 /2 操作,因为数学角度来说:x - i 和 x 的值
* 例如 x = 5 从 index = 1 砍一刀 木块变成了 4 , 1
* 从 index = 4 砍一刀 木块变成了 1 , 4
* 重复了,所以说 / 2
*
* */
for (int k = 1; k <= j / 2; k++)
dp[i][j] = max(dp[i][j], dp[i][k] + dp[i][j - k]);
/*
* 横着砍,物理的横着 一 这样砍木块
* */
for (int k = 1; k <= i / 2; k++)
dp[i][j] = max(dp[i][j], dp[k][j] + dp[i - k][j]);
}
}
return dp[m][n];
}
};
int main() {
Solution s;
s.sellingWood(3, 5, {{1, 4, 2},
{2, 2, 7},
{2, 1, 3}});
return 0;
}