问题描述:
上面的描述是一个三维的装箱问题,但是题目说大箱子的长度和小箱子的长度相同,所以可以转换为一个二维空间上的装箱问题,只考虑宽和高。
思考:
- 怎么装才能保证装的最多?从最小的开始装,装到装不下了就是最多的情况。(背包问题)
- 但是小方块不规则,会有很多空隙存在,那么在计算剩余空间的时候,用剩余总空间减去当前小方块的空间这样的做法是有问题的,因为小方块不可能像理想的那样紧凑的在一起。
解决方法:
- 要装下最多,首先能确定的是空间小的优先是能保证装的最多。
- 要能充分的利用空间,但是又不能以理想的方式直接用总的减去当前的。其实用二分的方法可以充分的利用空间,就是将第一个矩形放入盒子后,将盒子分为右、下两个盒子,然后继续在右和下两个盒子中装第二个矩形,然后装下了又划分。(参考)
- 上面解决了装最多,和充分利用空间的问题,但是充分利用空间的方法是从大开始装,因为这样划分的空间才有可能装下后面比它小的矩形。要是从最小的开始装,那么划分后剩余的空间是装不下还比它大的矩形的。所以1和2两个思路分别解决了问题,但是矛盾了。
- 那么又要优先装小的,又要从大的开始装。怎么解决? 我的思路是:从大的开始装,装到装不下了,看是否有剩余的小矩形,如果有!那么把最大的一个矩形剔除,从第二大的开始装,重复上面步骤,知道最小的一个装到盒子里面,那么这样的情况一定是最多而且最紧凑的。
代码的实现:
节点类 Node.java
public class Node {
public Integer x;
public Integer y;
public Integer w;
public Integer h;
public boolean isUsed;
public Node right;
public Node down;
public Rectangle rec;
public Node() {
}
public Node(Integer x, Integer y, Integer w, Integer h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public Integer getX() {
return x;
}
public void setX(Integer x) {
this.x = x;
}
public Integer getY() {
return y;
}
public void setY(Integer y) {
this.y = y;
}
public Integer getW() {
return w;
}
public void setW(Integer w) {
this.w = w;
}
public Integer getH() {
return h;
}
public void setH(Integer h) {
this.h = h;
}
public boolean isUsed() {
return isUsed;
}
public void setUsed(boolean used) {
isUsed = used;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public Node getDown() {
return down;
}
public void setDown(Node down) {
this.down = down;
}
public Rectangle getRec() {
return rec;
}
public void setRec(Rectangle rec) {
this.rec = rec;
}
}
核心类 Core.java
public class Core {
private Node root;
private Integer templateWidth;
private Integer templateHeight;
public List<Rectangle> datas;
public Core(List<Rectangle> datas,Integer templateWidth, Integer templateHeight) {
this.templateWidth = templateWidth;
this.templateHeight = templateHeight;
this.datas = datas;
}
public Node paking(){
this.root = new Node(0,0,templateWidth,templateHeight);
for (Rectangle item : datas){
if(!item.isUsed){//没有装入
Node currentNode = this.findNode(root,item);
if (currentNode != null){//装下去了
this.splitPlate(currentNode,item);//划分
item.isUsed = true;
}
else {
return this.root;
}
}
}
return this.root;
}
private Node findNode(Node root,Rectangle rectangle){
if (root.isUsed){//已经划分成两块(右 下)
Node node = findNode(root.right,rectangle);
if (node == null){//左边装不下
node = findNode(root.down,rectangle);//从右边装
}
return node;
} else if (rectangle.w <= root.w && rectangle.h <= root.h){//区间能装下小矩形
root.setRec(rectangle);
return root;
}else {//装不下了
return null;
}
}
private Node splitPlate(Node node,Rectangle rectangle){//划分容器
node.isUsed = true;//s说明容器已经划分了
node.down = new Node(node.x,rectangle.h,node.w,node.h-rectangle.h);//x,y,w,h
node.right = new Node(node.y,rectangle.w,node.w-rectangle.w,rectangle.h);
return node;
}
}
欢迎评论留言交流
留个群,嘻嘻嘻