二维装箱怎么能装最多

问题描述:
在这里插入图片描述
上面的描述是一个三维的装箱问题,但是题目说大箱子的长度和小箱子的长度相同,所以可以转换为一个二维空间上的装箱问题,只考虑宽和高。
思考:

  1. 怎么装才能保证装的最多?从最小的开始装,装到装不下了就是最多的情况。(背包问题)
  2. 但是小方块不规则,会有很多空隙存在,那么在计算剩余空间的时候,用剩余总空间减去当前小方块的空间这样的做法是有问题的,因为小方块不可能像理想的那样紧凑的在一起。

解决方法:

  1. 要装下最多,首先能确定的是空间小的优先是能保证装的最多。
  2. 要能充分的利用空间,但是又不能以理想的方式直接用总的减去当前的。其实用二分的方法可以充分的利用空间,就是将第一个矩形放入盒子后,将盒子分为右、下两个盒子,然后继续在右和下两个盒子中装第二个矩形,然后装下了又划分。(参考
  3. 上面解决了装最多,和充分利用空间的问题,但是充分利用空间的方法是从大开始装,因为这样划分的空间才有可能装下后面比它小的矩形。要是从最小的开始装,那么划分后剩余的空间是装不下还比它大的矩形的。所以1和2两个思路分别解决了问题,但是矛盾了。
  4. 那么又要优先装小的,又要从大的开始装。怎么解决? 我的思路是:从大的开始装,装到装不下了,看是否有剩余的小矩形,如果有!那么把最大的一个矩形剔除,从第二大的开始装,重复上面步骤,知道最小的一个装到盒子里面,那么这样的情况一定是最多而且最紧凑的。

代码的实现:

节点类 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;
    }
}

欢迎评论留言交流
留个群,嘻嘻嘻
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值