2312. 卖木头块(LeetCode)

给你两个整数 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;
}

 

  • 34
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值