問題描述:
上面的描述是一個三維的裝箱問題,但是題目說大箱子的長度和小箱子的長度相同,所以可以轉換爲一個二維空間上的裝箱問題,只考慮寬和高。
思考:
- 怎麼裝才能保證裝的最多?從最小的開始裝,裝到裝不下了就是最多的情況。(揹包問題)
- 但是小方塊不規則,會有很多空隙存在,那麼在計算剩餘空間的時候,用剩餘總空間減去當前小方塊的空間這樣的做法是有問題的,因爲小方塊不可能像理想的那樣緊湊的在一起。
解決方法:
- 要裝下最多,首先能確定的是空間小的優先是能保證裝的最多。
- 要能充分的利用空間,但是又不能以理想的方式直接用總的減去當前的。其實用二分的方法可以充分的利用空間,就是將第一個矩形放入盒子後,將盒子分爲右、下兩個盒子,然後繼續在右和下兩個盒子中裝第二個矩形,然後裝下了又劃分。(參考)
- 上面解決了裝最多,和充分利用空間的問題,但是充分利用空間的方法是從大開始裝,因爲這樣劃分的空間纔有可能裝下後面比它小的矩形。要是從最小的開始裝,那麼劃分後剩餘的空間是裝不下還比它大的矩形的。所以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;
}
}
歡迎評論留言交流
留個羣,嘻嘻嘻