最近工作中需要处理一个实际问题就是大箱子装小盒子的问题,写这篇文章需要解决的实际问题 就是大容器装小东西的问题。例如仓库中货位装载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
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)