Проблема с рекурсивным возвратом - PullRequest
0 голосов
/ 21 апреля 2011

Привет, ребята, недавно опубликовал сообщение о проблеме с моим алгоритмом.

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

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

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

// из предыдущего поста:

Как правило, набор передается этому методу ниже, и длина стержня также передается. Решение должно выводить числа из набора, которые дают минимальное количество отходов, если определенные числа из набора были удалены из длина бруса Итак, длина бара 10, набор включает в себя 6,1,4, таким образом, решение - это 6 и 4, а потери - 0. У меня возникли некоторые проблемы с условиями возврата обратно через набор. Я также пытался использовать «глобальную» переменную потерь, чтобы помочь с возвратом, но безрезультатно.

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

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

package recursivebacktracking;

/**
 *
 * @author User
 */
public class RecBack {

        int WASTAGE = 10;
        int BESTWASTAGE;
        int BARLENGTH = 10;

    public void work()
    {


         int[] nums = {6,1,2,5};
        //Order Numbers
        SetInt ORDERS = new SetInt(nums.length);
        SetInt BESTSET = new SetInt(nums.length);
        SetInt SOLUTION = new SetInt(nums.length);

        //Set Declarration


        for (int item : nums)ORDERS.add(item);
        //Populate Set

        SetInt result = tryCutting(ORDERS, SOLUTION, BARLENGTH, WASTAGE);
        result.printNumbers();


    }
    public SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft, int waste)
      {


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


            int a = possibleOrders.min(); //select next candidate
              System.out.println(a);

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



                if (!possibleOrders.isEmpty()) //solution not complete
                  {
                      System.out.println("this time");
                    tryCutting(possibleOrders, solution, lengthleft, waste);//try recursive call
                    BESTWASTAGE = WASTAGE;
                    if ( BESTWASTAGE <= WASTAGE )//if not successfull
                      {
                        lengthleft += a;
                        solution.remove(a);

                          System.out.println("never happens");
                      }

                  } //solution not complete
              }

          } //for loop

        return solution;

      }




}

1 Ответ

1 голос
/ 21 апреля 2011

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

Вот схема того, как вы это сделаете:

Пусть N будет количеством элементов в вашем наборе. Таким образом, если набор равен {6,1,2,5}, тогда N будет равно 4. Пусть max_waste будет максимальным отходом, который мы можем устранить (10 в вашем примере).

int best = 0;  // the best result so far

for (int mask = 1; mask <= (1<<N)-1; ++mask) {

    // loop over each bit in the mask to see if it's set and add to the sum
    int sm = 0;
    for (int j = 0; j < N; ++j) {
        if ( ((1<<j)&mask) != 0) {
            // the bit is set, add this amount to the total
            sm += your_set[j];

            // possible optimization: if sm is greater than max waste, then break
            // out of loop since there's no need to continue
        }
    }

    // if sm <= max_waste, then see if this result produces a better one
    // that our current best, and store accordingly
    if (sm <= max_waste) {
        best = max(max_waste - sm);
    }
}

Этот алгоритм очень похож на возврат и имеет аналогичную сложность, он просто не использует рекурсию.

Битовая маска в основном является двоичным представлением, где 1 указывает, что мы используем элемент в наборе, а 0 означает, что мы не используем. Поскольку мы выполняем цикл от 1 до (1<<N)-1, мы рассматриваем все возможные подмножества данных элементов.

Обратите внимание, что время работы этого алгоритма увеличивается очень быстро по мере увеличения N, но при N <= около 20 все должно быть в порядке. Кстати, то же самое относится и к возврату. Если вам нужна более высокая производительность, вам нужно рассмотреть другой метод, такой как динамическое программирование. </p>

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

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

EDIT Хорошо, я не осознавал, что вы должны использовать рекурсию.

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

Hint2 Если вам все еще нужны дополнительные подсказки, попробуйте подумать о том, что должна делать функция возврата. Каковы условия прекращения? Когда мы достигаем условия завершения, что нам нужно записать (например, получили ли мы новый лучший результат и т. Д.)?

Hint3 Оповещение о спойлере Ниже приведена реализация C ++, чтобы дать вам некоторые идеи, поэтому перестаньте читать здесь, если вы хотите поработать над этим самостоятельно.

int bestDiff = 999999999;
int N;
vector< int > cur_items;
int cur_tot = 0;
int items[] = {6,1,2,5};
vector< int > best_items;
int max_waste;

void go(int at) {
  if (cur_tot > max_waste)
    // we've exceeded max_waste, so no need to continue
    return;
  if (at == N) {
    // we're at the end of the input, see if we got a better result and
    // if so, record it
    if (max_waste - cur_tot < bestDiff) {
      bestDiff = max_waste - cur_tot;
      best_items = cur_items;
    }
    return;
  }

  // use this item  
  cur_items.push_back(items[at]);
  cur_tot += items[at];
  go(at+1);

  // here's the backtracking part
  cur_tot -= items[at];
  cur_items.pop_back();

  // don't use this item
  go(at+1);
}

int main() {
  // 4 items in the set, so N is 4
  N=4;

  // maximum waste we can eliminiate is 10
  max_waste = 10;

  // call the backtracking algo
  go(0);

  // output the results
  cout<<"bestDiff = "<<bestDiff<<endl;
  cout<<"The items are:"<<endl;
  for (int i = 0; i < best_items.size(); ++i) {
    cout<<best_items[i]<<" ";
  }
  return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...