实际问题应用逻辑|于Java简要的箱子放盒子的问题

最近工作中需要处理一个实际问题就是大箱子装小盒子的问题,写这篇文章需要解决的实际问题 就是大容器装小东西的问题。例如仓库中货位装载SKU 车厢里面装载快递包裹。
以下代码实现比较粗糙,实际过程中就是为了计算一个箱子中能装多少东西
前提条件
1、自己校验完 最长比较,即 小东西的 L(length) 、W(width)、 H(height) 最大值不能超过 大容器的LWH, 本文只讨论 立体箱子问题 杠精 读到这里就可以去逛其他帖子了,避免浪费你宝贵的时间。
大箱子 小盒子 基本属性类
CountBox

@Data @AllArgsConstructor public class CountBox {private Integer length; private Integer width; private Integer height; public Double getVol() { return (double) this.length*this.width*this.height; } }

对于计算 结合前人的计算方法 计算了一个朴素的算法 得到的结果不一定对 后面读者有更好的方式 ,请留言 让鄙人改进 以更好的适应
具体的方法类(可能个人习惯了Java 或者Spring 的注入特性的习惯,公共的方法就抽象出来做某一类业务或者某一种方法)
@Slf4j public class CountUtils {/** * 朴素计算(不计算之前已经装了的体积) 大箱子能装多少个小箱子 * @param maxBox * @param minBox * @return * 原理是: * nx < X * ny < Y * nz < Z * 交换 XYZ 比较顺序来计算各种方法最多能放多少个 取整乘积最大值就是可放置的最多个数(朴素算法) */ public Integer toCount(CountBox maxBox,CountBox minBox) { int a = ( (maxBox.getLength() / minBox.getLength()) * (maxBox.getWidth() / minBox.getWidth()) * (maxBox.getHeight() / minBox.getHeight()) ); int b = ( (maxBox.getLength() / minBox.getLength()) * (maxBox.getWidth() / minBox.getHeight()) * (maxBox.getHeight() / minBox.getWidth()) ); int c = ( (maxBox.getLength() / minBox.getWidth()) * (maxBox.getWidth() / minBox.getLength()) * (maxBox.getHeight() / minBox.getHeight()) ); int d = ( (maxBox.getLength() / minBox.getWidth()) * (maxBox.getWidth() / minBox.getHeight()) * (maxBox.getHeight() / minBox.getLength()) ); int e = ( (maxBox.getLength() / minBox.getHeight()) * (maxBox.getWidth() / minBox.getLength()) * (maxBox.getHeight() / minBox.getWidth()) ); int f = ( (maxBox.getLength() / minBox.getHeight()) * (maxBox.getWidth() / minBox.getWidth()) * (maxBox.getHeight() / minBox.getLength()) ); List capacitiesList = new ArrayList<>(); Stream.of(a, b, c, d, e, f).forEach(x -> capacitiesList.add(x)); return PrimeSortUtils.getMaxNumberFromArray(capacitiesList); }/** * 比较适用的现实的常规方法 计算前容器已完成了多少体积 * @param maxBox 大箱子 * @param minBox 小盒子 * @param occupyCapacity 已占用体积 * @return 所能承载的小盒子 */ private Integer toCountComplex(CountBox maxBox,CountBox minBox,Double occupyCapacity) { Integer a=0,b=0,c=0; //剔除所占空间的部分将该部分之外的体积分成若干个小的部分的box 进行朴素计算 Double totalCapacity = maxBox.getVol(); Double surplusCapacity = totalCapacity-occupyCapacity; Double minNeedVolume = minBox.getVol(); int minValue = https://www.it610.com/article/Math.min(minBox.getLength(),Math.min(minBox.getWidth(),minBox.getHeight())); if(surplusCapacity>minNeedVolume) { double maxLength = (surplusCapacity/(maxBox.getWidth()*maxBox.getHeight())); if(maxLength>minValue){ Integer lengthNew = (int)maxLength; CountBoxmaxBoxNew = new CountBox(lengthNew,maxBox.getWidth(),maxBox.getHeight()); a = toCount(maxBoxNew,minBox); } double maxWidth = (surplusCapacity/(maxBox.getLength()*maxBox.getHeight())); if(maxWidth>minValue){ Integer widthNew = (int)maxWidth; CountBoxmaxBoxNew = new CountBox(maxBox.getLength(),widthNew,maxBox.getHeight()); b = toCount(maxBoxNew,minBox); }double maxHeight = (surplusCapacity/(maxBox.getLength()*maxBox.getWidth())); if(maxHeight>minValue){ Integer heightNew = (int)maxHeight; CountBoxmaxBoxNew = new CountBox(maxBox.getLength(),maxBox.getWidth(),heightNew); c = toCount(maxBoxNew,minBox); } } return Math.max(a,Math.max(b,c)); }/** * 无视空间放置的计算方法( 限用) 只能针对同一个槽所有规格都一样 并且条件比较苛刻 至于后面怎么改造,后面抽时间再研究 * @param maxBox 大箱子 * @param minBox 小盒子 * @param occupyCapacity 已占用的体积 * @return 小盒子个数 */ public Integer toCountAll(CountBox maxBox,CountBox minBox,Double occupyCapacity) { Integer qty = 0; Integer count = 0; Double minBoxVolume = minBox.getVol(); while(true) { int tmp = toCountComplex(maxBox,minBox,(double)(occupyCapacity+qty*minBoxVolume)); if(tmp>0) { qty +=tmp; count ++; } else { break; } }log.info("First Recycle times is:{}",count); int minValue = https://www.it610.com/article/Math.min(minBox.getLength(),Math.min(minBox.getWidth(),minBox.getHeight())); if(count>1) { Integer a = maxBox.getLength() - (count - 1) * minValue; Integer b = maxBox.getWidth() - (count - 1) * minValue; Integer c = maxBox.getHeight() - (count - 1) * minValue; int minSurplusVal = Math.min(a, Math.min(b, c)); Integer maxValue = https://www.it610.com/article/Math.max(minBox.getLength(), Math.max(minBox.getWidth(), minBox.getHeight())); if (maxValue <= minSurplusVal)//最长边 还小于最少递减值 即 理论上结合总体积比较还可以放得下 { CountBox maxBoxNew = new CountBox(a, b, c); Double theoreticalVol = maxBoxNew.getVol(); Double surplusVol = maxBox.getVol() - occupyCapacity - qty * minBoxVolume; if (theoreticalVol> surplusVol) { maxBoxNew.setLength(Math.max(minBox.getLength(), Math.max(minBox.getWidth(), minBox.getHeight()))); Double theoreticalVolNew = maxBoxNew.getVol(); if (theoreticalVolNew > surplusVol) { maxBoxNew.setWidth(Math.max(minBox.getLength(), Math.min(minBox.getWidth(), minBox.getHeight()))); maxBoxNew.setHeight(Math.max(minBox.getLength(), Math.min(minBox.getWidth(), minBox.getHeight()))); Double theoreticalVolNew2 = maxBoxNew.getVol(); if (theoreticalVolNew2 > surplusVol) { Double theoreticalVolNew3 = maxBoxNew.getVol(); if (theoreticalVolNew3 > surplusVol) { maxBoxNew.setHeight(Math.min(minBox.getLength(), Math.min(minBox.getWidth(), minBox.getHeight()))); } } } } Integer qty2 = toCountComplex(maxBoxNew, minBox, 0D); qty += qty2; } } return qty; }public static void main(String[] args) {CountUtils countUtils = new CountUtils(); CountBox maxBox = new CountBox(5,5,5); CountBox minBox = new CountBox(1,2,3); Integer firstQty = countUtils.toCountComplex(maxBox,minBox,0D); System.out.println(firstQty); Integer secondQty = countUtils.toCount(maxBox,minBox); System.out.println(secondQty); Integer thridQty = countUtils.toCountAll(maxBox,minBox2,0D); System.out.println(thridQty); } }

自己测试过很多组数据 其中 对于解决实际问题的话 countComplex 话已经是比较好解决实际问题的,原因就是:理论计算方法对于实际生产的出入比较大,简单点说空间全部占满 当手都伸不进去了 小盒子怎么拿出来,当有容器包裹物体,空间装满 物体是无法拿出来的额。
1、toCount方法比较简易 也是默认算法 立体空间放置旋转九十度的原理
2、基于此类问题大都是NPL 问题,比较浪费时间,得出简易结果其实就能解决实际问题了
3、楼主不是专注于算法研究,所以该方法还有得改进,希望遇见贵人,能优化下计算过程。
有兴趣的技术大佬 帮忙想下 123 的盒子 和116 的盒子 在满足能够放下两种规格盒子的箱子里(就比如 654),能够放的数量是一样的吗??简化问题 已占空间 都设置成0 分析吧 。
实际生活中这种大箱子可能装的不是同一种规格的货,所以体积肯定不一样,只能每次减去已占用的体积重新分析计算
有建设性建议还可以留言,谢谢!
【实际问题应用逻辑|于Java简要的箱子放盒子的问题】某些问题计算逻辑文库(外国仁的维基百科(We need to turn over the wall)):
https://en.wikipedia.org/wiki/Packing_problems

    推荐阅读