程序员面试金典(堆箱子)
题目描述
有一堆箱子,每个箱子宽为wi,长为di,高为hi,现在需要将箱子都堆起来,而且为了使堆起来的箱子不倒,上面的箱子的宽度和长度必须小于下面的箱子。请实现一个方法,求出能堆出的最高的高度,这里的高度即堆起来的所有箱子的高度之和。
给定三个int数组w,l,h,分别表示每个箱子宽、长和高,同时给定箱子的数目n。请返回能堆成的最高的高度。保证n小于等于500。
测试样例:
[1,1,1],[1,1,1],[1,1,1]
返回:1
思路:按箱子的宽度降序序列,如果两个箱子宽度相等,则比较两个箱子的长度,长度较长的排前面,然后直接进行深度优先搜索就可以了,因为排过序,对于第i个箱子,可能能够堆在第i个箱子上面的只有第i+1到n之间的箱子,第i个箱子之前的一定是不可能再堆到第i个箱子上面的,所以我们只管尝试添加第i个之后的箱子,题目给定的问题规模是500,就算前面进行了剪枝也会严重超时,所以可以采用记忆型递归。
import java.util.*;
public class Box {
public int getHeight(int[] w, int[] l, int[] h, int n) {
// write code here
dp = new int[n];
//为了方便排序,可以将w,l,l封装成结构体
Node nodes[] = new Node[n];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new Node(w[i],l[i],h[i]);
}
Arrays.sort(nodes);
return dfs(nodes,0,n,Integer.MAX_VALUE,Integer.MAX_VALUE);
}
int []dp;
public int dfs(Node nodes[],int cur,int n,int prew,int prel)
{
if(cur==n) return 0;
if(dp[cur]!=0) return dp[cur];
int max = 0;
for (int i = cur; i < n; i++) {
if(nodes[i].w<prew&&nodes[i].l<prel)
{
max = Math.max(max, nodes[i].h+dfs(nodes, i+1, n, nodes[i].w, nodes[i].l));
}
}
return dp[cur] = max;
}
class Node implements Comparable<Node>{
int w,l,h;
public Node(int w, int l, int h) {
this.w = w;
this.l = l;
this.h = h;
}
@Override
public int compareTo(Node o) {
// TODO Auto-generated method stub
//如果两个箱子的宽度相等,则比较长度
if(this.w==o.w) return -(this.l-o.l);
//如果箱子宽度不等,直接比较宽度
return -(this.w-o.w);
}
}
}