我有如下的家庭作业:
垃圾箱包装问题是包装物品 各种重量的容器。假设每一个 容器最多可容纳10磅。该 程序使用将对象放入的算法 它适合的第一个垃圾箱。你的程序应该 提示用户输入对象总数 和每个物体的重量。程序显示 包装所需的容器总数 对象和每个容器的内容。这里有一个 简单的程序运行:
现在我决定尝试使其更智能并优化对象分配。它看起来工作正常,但是当我开始使用比样本运行更多的数字进行测试时,我注意到我可以使用的最高数量是27个对象。任何更高的东西,我开始在执行结束时获得一些容器,可以合并为一个容器。欢迎任何想法和建议。提前谢谢!
package classwork;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import java.util.Scanner;
public class BinPacking {
private static final int binLimit = 10;
public static boolean lessThanLimit(int a, int b) {
if (a + b < binLimit) {
return true;
} else {
return false;
}
}
public static boolean perfectFit(int a, int b) {
if (a + b == binLimit) {
return true;
} else {
return false;
}
}
public static boolean weightsLeft(boolean[] a) { // check if there is one more item that has not been binned yet.
for (boolean b : a) {
if (b) {
return true;
}
}
return false;
}
public static ArrayList<int[]> distributeObjects(int[] weights) {
int counter = 0;
boolean[] objectAssigned = new boolean[weights.length]; // array to track which objects have been assigned already
ArrayList<int[]> result = new ArrayList<int[]>(); // list of int[] to be returned
for (int i = 0; i < weights.length; i++) {
ArrayList<Integer> currentBin = new ArrayList<Integer>(); // list to store the values of the weights in currrent bin
int currentBinWeight = 6;
if (!objectAssigned[i]) {
currentBin.add(weights[i]);
currentBinWeight = weights[i];
objectAssigned[i] = true;
} else
counter = 1;
stupidLoopThatWontBreak:
while (currentBinWeight < binLimit && counter < 1) {
counter = 1;
if (!weightsLeft(objectAssigned)) { // break loop if no more weights left
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
break stupidLoopThatWontBreak;
}
for (int j = i + 1; j < weights.length; j++) {
if (perfectFit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight += weights[j];
objectAssigned[j] = true;
break stupidLoopThatWontBreak;
}
if (lessThanLimit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBinWeight += weights[j];
currentBin.add(weights[j]);
objectAssigned[j] = true;
}
}
}
// convert arraylist to int[] and add it to result. Java 8+ feature
if (!currentBin.isEmpty()) {
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
counter = 0;
}
}
return result;
}
public static void main(String[] args) {
System.err.println("Container weight limit is " + binLimit);
Scanner in = new Scanner(System.in);
//Test numbers 7, 5, 3, 2, 5, 8
// System.out.print("Enter the weights of the objects you want to put into the bins: ");
// String input = in.nextLine();
// in.close();
//========================Random numbers for testing======================
String input = "";
Random ran = new Random();
System.out.print("Enter number of weights to be randomly generated: ");
int num = in.nextInt();
in.close();
for (int i = 0; i < num; i++) {
input += (ran.nextInt(binLimit) + 1) + " "; //+1 to not have zeroes
}
//========================End of random numbers===========================
ArrayList<Integer> list = new ArrayList<Integer>();
String[] str = input.trim().split(" "); // trim surrounding spaces, use space char as separator
for (String a : str) {
list.add(Integer.valueOf(a));
}
// sort the list in a descending order
Collections.sort(list);
Collections.reverse(list); // this could be avoided if I started checking from the last index in distributeObjects()
System.out.println("The generated and sorted descendingly weights are:");
System.out.println("\n" + list.toString() + "\n");
int[] weights = new int[list.size()];
for (int a = 0; a < weights.length; a++) {
weights[a] = list.get(a);
}
ArrayList<int[]> bins = distributeObjects(weights);
for (int i = 0; i < bins.size(); i++) {
System.out.println("Container " + (i + 1) + " contains objects with weight: " + Arrays.toString(bins.get(i)));
}
}
}
答案 0 :(得分:0)
由于我无法发表评论,我将此作为答案 -
使用“10 9 8 8 8 7 7 7 6 6 6 5 5 5 4 4 4 4 4 3 3 2 2 2 2 2 2 2 1 1”作为输入数组运行以上代码,您将看到问题所在通过'counter'变量。如果你替换'counter = 1;'来自其他的'继续;'它应该适用于这个输入。您仍需要针对其他输入进行测试。此外,上面的代码需要重构 - 例如 - 使用列表或权重。两者都是必需的。
答案 1 :(得分:0)
我尽量不要过多地扭曲你的代码,但这应该会给你你想要的输出。问题在于你的第二个循环,它导致了计数器变量的一些问题,因为如果不应该已经添加了bin(当你没有找到第一个重量时,计数器在循环结束时从未设置回0)被添加到bin)。
修复程序最简单的方法就是在if语句中移动counter = 0;
,检查bin中是否有权重,或者if块之外是否有权重。
我删除了&#34; stupidLoopThatWouldNotBreak&#34;在下面并用另一个for循环替换它,如果有一个可以适合的话,它会查看所有剩余的权重。
public static ArrayList<int[]> distributeObjects(int[] weights) {
boolean[] objectAssigned = new boolean[weights.length]; // array to track which objects have been assigned already
ArrayList<int[]> result = new ArrayList<int[]>(); // list of int[] to be returned
for (int i = 0; i < weights.length; i++) {
ArrayList<Integer> currentBin = new ArrayList<Integer>(); // list to store the values of the weights in currrent bin
int currentBinWeight = 0;
//This loop searches for the first unused Weight, so you do not need `count` anymore
for (int j = i; j < weights.length; j++) {
if (!objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight = weights[j];
objectAssigned[j] = true;
break;
}
i = j; //You can skip all iterations with used weights
}
for (int j = i; j < weights.length && currentBinWeight < binLimit; j++) {
if (perfectFit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight += weights[j];
objectAssigned[j] = true;
break; //this break gives some performance bonus
}
if (lessThanLimit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBinWeight += weights[j];
currentBin.add(weights[j]);
objectAssigned[j] = true;
}
}
// convert arraylist to int[] and add it to result. Java 8+ feature
if (!currentBin.isEmpty()) {
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
}
}
return result;
}
如果拆分此循环,则可以进一步增强代码。您可以添加更多功能,例如两个辅助功能perfectFit
和lessThanlimit
。例如,您可以添加另一个将搜索第一个空元素的函数,甚至可以将其添加到bin中。此外,您已经拥有的2个函数可以合并为一个名为addWeight
或attemptAdd
的函数。此外,您可以为bin和权重创建单独的类。