Поиск номеров из набора, которые дают минимальное количество отходов

Далее передается набор, и длина строки также передается. Решение должно выводить числа из набора, которые дают минимальное количество отходов, если определенные номера из набора были удалены из бара длина. Таким образом, длина бара 10, набор включает 6,1,4, поэтому решение составляет 6 и 4, а потеря равна 0. У меня есть некоторые проблемы с условиями, чтобы отступить, хотя набор. Ive также попытался использовать "глобальную" переменную потерь, чтобы помочь в аспекте обратного отслеживания, но безрезультатно.

SetInt - это реализация, выполненная вручную, которая может добавлять, удалять, проверять, пуст ли пуст и вернуть минимальное значение из набора.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package recback;


public class RecBack {

   public static int WASTAGE = 10;

    public static void main(String[] args) {



         int[] nums = {6,1,4};
        //Order Numbers

        int barLength = 10;
        //Bar length

        SetInt possibleOrders = new SetInt(nums.length);
        SetInt solution = new SetInt(nums.length);
        //Set Declarration


        for (int i = 0; i < nums.length; i++)possibleOrders.add(nums[i]);
        //Populate Set

        SetInt result = tryCutting(possibleOrders, solution, barLength);
        result.printNumbers();


    }

    private static SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft)
      {



        SetInt clonedSet = possibleOrders.cloneSet(); //initialise selection of candidates

        for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
          {

            int a = clonedSet.min(); //select next candidate

            if (a <= lengthleft) //if accecptable
              { 
                solution.add(a); //record candidate
                lengthleft -= a;
                clonedSet.remove(a); //remove from original set

                if (!clonedSet.isEmpty()) //solution not complete
                  {
                    WASTAGE +=a;
                    tryCutting(clonedSet, solution, lengthleft);//try recursive call

                    if (lengthleft > WASTAGE)//if not successfull
                      {
                        WASTAGE += a;
                        solution.remove(a);
                      }

                  } //solution not complete
              }
          } //for loop
        return solution;

      }
  }

Ответ 1

У вас есть пара проблем.

Один из них: int a = clonedSet.min(); //select next candidate

Если вы пройдете через ваш пример, он найдет значение 1 и первым будет использовать его, поэтому 1 и 4 будут использованы, но 6 не будут.

Вам лучше искать максимальное значение, которое будет <= оставшаяся длина.

Эта строка также нечетна для меня:

WASTAGE +=a;

Вы должны вычитать, я думаю, и почему вы изменяете статическое целое?

Если это то, что может быть изменчивым, тогда вы должны просто передать его, а затем вернуться, когда закончите, какая сумма была потрачена впустую, так что вы получите новый класс, решение и сумму, которая была потрачена впустую.

Для рекурсии вы захотите иметь свой пример, затем пройдитесь по одному за раз и посмотрите, будет ли поведение, которое оно делает, то, что вы ожидаете.

Вы можете посмотреть этот цикл:

for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat

Как если бы вы делали это рекурсивно, то, если у вас есть 3 возможных решения, вы, скорее всего, сделаете 6 тестов, а не три раза, что вы ожидаете.

Если вы удалите цикл for, вы все равно должны быть в порядке. Поместите выражение печати, чтобы вы могли смотреть его каждый раз.

UPDATE:

Основываясь на дополнительной информации, то, что вы хотите сделать, это собрать все возможные решения, то, что вы можете сделать, это пройти и сделать первый проход, получить решения, которые работают именно так. Затем сдвиньте влево или вправо возможные решения, затем повторите попытку.

Когда вы переместились полностью, вы будете пробовать различные комбинации, но не любую возможную комбинацию, но затем вы можете принять эти решения и посмотреть, какой из них оптимален.

Если вы хотите протестировать больше комбинаций, вам нужно будет выполнить цикл, удалив элемент, и это может быть рекурсивным.

Итак, вам понадобится одна рекурсивная функция внутри другой, поэтому вы рекурсивно пройдете все возможные комбинации, а затем рекурсивно посмотрите на решение проблемы.

Я думаю, что поиск max, вероятно, был бы лучшим, но это только мое чувство кишки, и можно было бы показать, что min лучше.

Ответ 2

Я согласен с Джеймсом, вам не нужен/нужен цикл. Насколько я понимаю, ваш алгоритм tryCutting отображает список возможных заказов, текущее решение и оставшуюся длину, если вы хотите сократить текущее решение. Затем вам нужно:

  • удалите кратчайший из заказы. Если длина больше длины, не пытайтесь больше. В противном случае
  • первый случай: вы не выполняете что cut-tryCutting снова с новым список заказов и тот же ток длина
  • второй случай: вы выполняете это порез. Добавьте его к текущему решение и tryCutting с новым списком заказов и длиной уменьшенный этим разрезом. Наконец, возьмите он снова отменит текущее решение (для backtracking)
  • поставьте кратчайший назад для заказов (для возврата)

Теперь, для каждого случая, который вы пытаетесь, проверьте длину, оставшуюся до вашего глобального наилучшего случая. Это короче, чем обновление глобального (с клоном) текущего решения.

Это даст вам единственное лучшее решение или одно из них, если есть несколько одинаково хороших. Чтобы получить все решения, вам нужен глобальный список SetInts. Если вы найдете решение лучше, чем текущее, очистите список и добавьте новое решение. Если он равен текущему лучшему, просто добавьте его.

Здесь он находится в коде:

public static void main(String[] args) {
    int[] nums = {6,1,4};          //Order Numbers
    int barLength = 10;         //Bar length
    bestSolution = new HashSet<SetInt>();
    bestWastage = barLength;
    SetInt possibleOrders = new SetInt(nums.length);
    SetInt solution = new SetInt(nums.length);         //Set Declarration
    for (int i = 0; i < nums.length; i++) {
        possibleOrders.add(nums[i]);         //Populate Set
    }
    tryCutting(possibleOrders, solution, barLength);
    for (SetInt result : bestSolution) {
        result.printNumbers();
    }

}

private static int bestWastage;
private static Set<SetInt> bestSolution;

private static void tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft) {
    if (lengthleft < bestWastage) {
        // Better than the best solution
        bestWastage = lengthleft;
        bestSolution.clear();
        bestSolution.add(solution.cloneSet());
    } else if (lengthleft == bestWastage) {
        // Just as good as the best solution
        bestSolution.add(solution.cloneSet());
    }
    int a = possibleOrders.min(); //select next candidate
    if (a <= lengthleft) { // If acceptable
        possibleOrders.remove(a); // Remove it
        tryCutting(possibleOrders, solution, lengthleft); // Try without that cut
        solution.add(a); // add to the solution
        tryCutting(possibleOrders, solution, lengthleft - a); // Try with that cut
        solution.remove(a); // remove again
        possibleOrders.add(a); // add the candidate back on again
    }
}