leetcode 面试题 08.13. 堆箱子 经典dp 套娃问题

面试题 08.13. 堆箱子

堆箱子。给你一堆n个箱子,箱子宽 wi、深 di、高 hi。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一种方法,搭出最高的一堆箱子。箱堆的高度为每个箱子高度的总和。

输入使用数组[wi, di, hi]表示每个箱子。

示例1:

输入:box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
输出:6

示例2:

输入:box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]
输出:10

提示:

箱子的数目不大于3000个。

  • 箱子套娃问题,
    1. 当一个箱子的长宽高完全大于另一个才能发生转移
    2. 按某一维度排序,则答案必是其中一个子序列

转移方程 :

  • 当箱子能够完全套入时,发生转移
  • d p [ i ] = m a x ( d p [ i ] , d p [ j ] + h e i g h t [ i ] ) dp[i] = max(dp[i], dp[j]+height[i]) dp[i]=max(dp[i],dp[j]+height[i])
  • 初始状态 : d p [ i ] = h e i g h t [ i ] dp[i] = height[i] dp[i]=height[i] 因为至少有一个箱子可作为答案
/**
 * 箱子套娃问题,
 *     1. 当一个箱子的长宽高完全大于另一个才能发生转移
 *     2. 按某一维度排序,则答案必是其中一个子序列
 * 动态规划 : 
 *     dp[i] 表示长度为 i 的最优解
 *     想求dp[i]就必须先求出dp[i-1]
 *     转移方程 : 
 *          当箱子能够完全套入时,发生转移
 *          dp[i] = max(dp[i], dp[i-1]+height[i])
 *     初始状态 : dp[i] = height[i] 因为至少有一个箱子可作为答案
 */

int dp[MAXN];

bool cmp(vector<int>& va, vector<int>& vb) { return va[0] < vb[0]; }

class Solution {
public:
    int pileBox(vector<vector<int>>& mtx) {
        memset(dp, false, sizeof(dp));
        int n = mtx.size(), ans = 0;
        sort(mtx.begin(), mtx.end(), cmp); //按照第一维度排序
        for(int i=0; i<n; i++) {
            dp[i] = mtx[i][2]; //边界条件 至少有一个箱子
            for(int j=0; j<i; j++) {
                //当前箱子能够完全套入时才进行转移
                if(mtx[j][0]<mtx[i][0] && mtx[j][1]<mtx[i][1] && mtx[j][2]<mtx[i][2]) {
                    dp[i] = max(dp[i], dp[j]+mtx[i][2]);
                }
            } 
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

java


import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

@SuppressWarnings("all") //压制所有警告
class Solution {
    static int dp[] = new int[Main.MAXN];
    public int pileBox(int[][] mtx) {
        Arrays.sort(mtx, 0, mtx.length, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0];
            }
        });

        int n = mtx.length, m = mtx[0].length, ans = -0x3f3f3f3f;
        for(int i=0; i<n; i++) {
            dp[i] = mtx[i][2];
            for(int j=0; j<i; j++) {
                if(mtx[j][0]<mtx[i][0] && mtx[j][1]<mtx[i][1] && mtx[j][2]<mtx[i][2]) {
                    dp[i] = Math.max(dp[i], dp[j]+mtx[i][2]);
                }
            }
            ans = Math.max(ans, dp[i]);
        }
        return ans;
    }
}

public class Main {
    public static final boolean debug = true;
    public static String INPATH = "C:\\Users\\majiao\\Desktop\\test.txt",
            OUTPATH = "C:\\Users\\majiao\\Desktop\\out.txt";
    public static StreamTokenizer tok;
    public static BufferedReader cin;
    public static PrintWriter cout;

    public static long start_time = 0, out_time = 0;
    public static int n, m, K, Q, MAXN = (int)1e5+7, INF = 0x3f3f3f3f;
    public static byte buf[] = new byte[MAXN];

    public static void main(String[] args) throws IOException {
        main_init();
        if(debug) { start_time = System.currentTimeMillis(); }
        if(false) { System.setOut(new PrintStream(OUTPATH)); }

        int mtx[][] = {{1, 1, 1}, {2, 3, 4}, {2, 6, 7}, {3, 4, 5}};
        Solution s = new Solution();
        cout.printf("%d\n", s.pileBox(mtx));

        if(debug) {
            out_time = System.currentTimeMillis();
            cout.printf("run time : %d ms\n", out_time-start_time);
        }
        cout.flush();
    }

    @Deprecated //标记方法已过时 不建议使用
    public static void main_init() {
        try {
            if (debug) {
                cin = new BufferedReader(new InputStreamReader(
                        new FileInputStream(INPATH)));
            } else {
                cin = new BufferedReader(new InputStreamReader(System.in));
            }
            cout = new PrintWriter(new OutputStreamWriter(System.out));
//            cout = new PrintWriter(OUTPATH);
            tok = new StreamTokenizer(cin);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String next_str() {
        try {
            tok.nextToken();
            if (tok.ttype == StreamTokenizer.TT_EOF)
                return null;
            else if (tok.ttype == StreamTokenizer.TT_NUMBER) {
                return String.valueOf((int)tok.nval);
            } else if (tok.ttype == StreamTokenizer.TT_WORD) {
                return tok.sval;
            } else return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static int read_int() {
        String tmp_next_str = next_str();
        return null==tmp_next_str ? -1 : Integer.parseInt(tmp_next_str);
    }
    public static long read_long() { return Long.parseLong(next_str()); }
    public static double read_double() { return Double.parseDouble(next_str()); }
    public static BigInteger read_big() { return new BigInteger(next_str()); }
    public static BigDecimal read_dec() { return new BigDecimal(next_str()); }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值