问题:
有若干个箱子,假设每个箱子的最大承重为 MaxW 。有一批物品,它们的重量分别为w1、w2...Wn,假设每个物品的重量都不超过箱子承重。
写个算法,用最少的箱子装完所有物品,并列出每个箱子装载的物品重量?
举个例子:
int[] Wn={8,5,19,5,5,11,5,4,2,17}
int MaxW=20
最少箱子数应该是4个,每个箱子装的物品的重量分别是 {11,5,4} {8,5,5,2} {19} {17}
PS:能用代码大佬可以直接上代码,能讲思路的就直接讲思路
这貌似就是贪心。
昨晚睡觉前,突然灵感来了,用了一个循环和回溯搞定了,但不知道是不是最合理的解决方案
首先至少5个,你少一个5的物品
思路:
1.数组排序
2.增序或逆序遍历数组,在数组中找跟(MaxW-win[i])最相近的
3.直到数组遍历完成
首先非常感谢朋友给解题思路,此法最先就已尝试,可能是能力有限,没能实现,不过现在已经用另一种方法实现了,再次感谢
如果只有一个箱子,应该是背包问题(动态规划),现在有多个箱子,那就再加上贪心。
MaxW
for Wi in Wn
{
//箱子装一件
if Wi==MaxW 则 Wi 装箱子
}
for Wi,Wj in Wn
{
//箱子装两件
if Wi+Wj ==MaxW 则 Wi、Wj 装箱子
}
//箱子装n件
。。。
直到任意的 n 件都大于 MaxW结束(在实现时可以人为设定下,比如一个箱子最多装4件,就是4次for)
---------------------------------------------------------------------------
MaxW=MaxW-1;
再重复分割线上面的;
---------------------------------------------------------------------------
理论上这个出来的是最优解,但复杂度模型有问题。
我在这方面经验不多,想到的方法比较笨。
先给数组排序,从小到大~,然后 开始从前往后加和,加到第n个若大于maxw 就给箱子计数加1~然后 再从第n个数开始加和。。后面的以此类推
代码:
public static void main(String[] args){
//初始化长度为50的数组
Integer[] ints=new Integer[20];
//使用随机数机制,随机获取小于20的50个整数,添加到数组
for(int i=0;i<ints.length;i++){
ints[i]=(int)(1+Math.random()*20);
System.out.print(ints[i]+" ");
}
//使用选择排序将数据由大到小排序
int tmp;
for(int i=0;i<ints.length;i++){
for (int j=0;j<ints.length;j++){
if(ints[i]>ints[j]){
tmp=ints[i];
ints[i]=ints[j];
ints[j]=tmp;
}
}
}
System.out.println();
//集合排序后,打印输出
for(int i=0;i<ints.length;i++){
System.out.print(ints[i]+" ");
}
System.out.println();
//实现随机组合装箱为20容积的箱子
//如何去获取装箱组合
int max=20;//初始化箱子的容积
int identSub=ints.length-1;//初始化由后到前取数组元素的下标
int element=0;//初始化获取的数组元素相加的和
int groupNum=0;//初始化组合的数量为0
//从前向后取集合中的每个数据
out:for(int i=0;i<ints.length;i++){
//每一次的第一层循环都将数组相加和设置为0
element=0;
System.out.print("{");
element=ints[i];
System.out.print(ints[i]+" ");
//从后向前取每个元素数据,但需要添加标识,记录下次取数的位置
for(;identSub>i;identSub--){
element+=ints[identSub];
//判断当前获取的前后值和是否大于了箱子的容积,如果大于跳出本次循环
if (element>max){
groupNum++;
break;
}
System.out.print(ints[identSub]+" ");
}
//如果前后获取到同一个数据时,就跳出整个嵌套循环
if(identSub==i){
System.out.println("}");
groupNum++;
break;
}
System.out.print("}");
System.out.println();
}
System.out.println("需要使用"+max+"容积的箱子数为:"+groupNum);
}
代码执行结果:
3 15 14 19 13 4 10 4 20 3 1 7 13 8 18 18 20 5 9 8
20 20 19 18 18 15 14 13 13 10 9 8 8 7 5 4 4 3 3 1
===组合装箱开始===
{20 }
{20 }
{19 1 }
{18 }
{18 }
{15 3 }
{14 3 }
{13 4 }
{13 4 }
{10 5 }
{9 7 }
{8 8 }
===组合装箱结束===
需要使用20容积的箱子数为:12
虽然过去这么久了,没想到还有人回帖,很感谢哈,不过这个这位朋友的算法不正确
思路是这样的,要想箱子最少,那么装箱的重量最好等于20,次之则逼近20.
用20与这个10个数做差int[] Wn={8,5,19,5,5,11,5,4,2,17}
int MaxW=20
那么差值集合是int [] Wn1={12,15,1,15,15,9,15,16,18,3}
最理想的最小值为P=(8+5+19+5+5+11+5+4+2+17)/20=81/20大于4
最理想的最大值为Q=数组的长度=10,总重量为81吨,最重承重为20,起码要5个。
楼主的4个肯定是错的,最理想情况下也要5个,楼主答案里少了个5,数组是10个数好么?
所以可以确定范围是5到10个,如果是10箱,浪费的运量L=10*20-81=119,119/20<6
所以可以确定理论上的最小值为5,那么考虑实际上会有偏差,所以最小值要么是5要么是6
然后算法验证:
for(int i=0;i<wn.length;i=i+n){
while(wn[i]+wn[i+1]+....wn[i+n])>20{
print(wn[i],wn[i+1],wn[i+n-1])
}
}
{8,5}差集为{7}
{19}差集为{1}
{5,5}差集为{10}
{11,5,4}差集为{0}
{2,17}差集为{1}
差集和为19与20*5-81=19相验证且19<20可以确定是一组最优解理论上的最小值与实际符合。即为5.若将4改为3
则P=80.理论最小值为80/20=4.
但我们循环出来的结果为
{8,5}差集为{7}
{19}差集为{1}
{5,5}差集为{10}
{11,5,3}差集为{1}
{2,17}差集为{1}
这时实际值为5,理论值为4,怎么验证呢?差集中的最大值10与任一项的和相比。若差集10大,则为4,若差集10小则为5级理论值+1