面试题 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个。
- 箱子套娃问题,
- 当一个箱子的长宽高完全大于另一个才能发生转移
- 按某一维度排序,则答案必是其中一个子序列
转移方程 :
- 当箱子能够完全套入时,发生转移
- 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()); }
}