程序在某个阈值后开始行为不端

时间:2018-03-08 11:35:58

标签: java

我有如下的家庭作业:

  

垃圾箱包装问题是包装物品   各种重量的容器。假设每一个   容器最多可容纳10磅。该   程序使用将对象放入的算法   它适合的第一个垃圾箱。你的程序应该   提示用户输入对象总数   和每个物体的重量。程序显示   包装所需的容器总数   对象和每个容器的内容。这里有一个   简单的程序运行:

  • 输入对象数:6
  • 输入对象的重量:7 5 2 3 5 8
  • 容器1包含重量为7 2
  • 的物体
  • 容器2包含重量为5 3
  • 的物体
  • 容器3包含重量为5
  • 的对象
  • 容器4包含重量为8的对象

现在我决定尝试使其更智能并优化对象分配。它看起来工作正常,但是当我开始使用比样本运行更多的数字进行测试时,我注意到我可以使用的最高数量是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)));
    }

}

}

2 个答案:

答案 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;
}

如果拆分此循环,则可以进一步增强代码。您可以添加更多功能,例如两个辅助功能perfectFitlessThanlimit。例如,您可以添加另一个将搜索第一个空元素的函数,甚至可以将其添加到bin中。此外,您已经拥有的2个函数可以合并为一个名为addWeightattemptAdd的函数。此外,您可以为bin和权重创建单独的类。