Bin Packing - Рекурсивное решение методом грубой силы - Как сделать это быстрее - PullRequest
3 голосов
/ 29 ноября 2011

У меня есть массив, который содержит список материалов разных размеров: {4,3,4,1,7,8}.Тем не менее, в мусорное ведро могут поместиться материалы до размера 10. Мне нужно выяснить минимальное количество бункеров, необходимое для упаковки всех элементов в массиве.

Для указанного выше массива вы можете упаковать 3 бункера и разделитьих следующим образом: {4,4,1}, {3,7}, {8}.Существуют и другие возможные способы, которые также подходят для трех стандартных труб, но это невозможно сделать с меньшим количеством

. Я пытаюсь решить эту проблему с помощью рекурсии, чтобы лучше ее понять.

Яиспользуя эту формулировку DP (стр. 20 файла pdf)

Рассмотрим ввод (n1; :::; nk) с n = ∑nj элементами
Определить наборk-кортежей (подмножеств входных данных), которые могут быть упакованы в один бин
То есть все кортежи (q1; :::; qk), для которых OPT (q1; :::; qk) = 1
Обозначим это множество через Q. Для каждого набора из q мы имеем OPT (q) = 1
Рассчитать оставшиеся значения, используя повторение: OPT (i1; :::; ik) = 1 + minOPT (i1 -q1; :::; ik - qk)

Я сделал код, и он отлично работает для небольшого набора данных.Но если увеличить размер моего массива до более чем 6 элементов, он станет чрезвычайно медленным - занимает около 25 секунд, чтобы решить массив, содержащий 8 элементов Можете ли вы сказать мне, если что-то не так с алгоритмом?Мне не нужно альтернативное решение --- просто нужно знать, почему это так медленно, и как его можно улучшить

Вот код, который я написал на C ++:

void recCutStock(Vector<int> & requests,  int numStocks)
{
 if (requests.size() == 0)
 {

     if(numStocks <= minSize)
    {
        minSize = numStocks;

    }
//   cout<<"GOT A RESULT : "<<numStocks<<endl;
        return ;
 }
 else
 {
    if(numStocks+1 < minSize) //minSize is a global variable initialized with a big val
    {
     Vector<int> temp ; Vector<Vector<int> > posBins;
     getBins(requests, temp, 0 , posBins); // 2-d array(stored in posBins) containing all possible single bin formations

    for(int i =0; i < posBins.size(); i++)
    {
        Vector<int> subResult;
        reqMinusPos(requests, subResult,  posBins[i]);  // subtracts the initial request array from the subArray
        //displayArr(subResult);


            recCutStock(subResult,  numStocks+1);


    }
    }
    else return;
 }

}

Функция getBins выглядит следующим образом:

void getBins(Vector<int> & requests, Vector<int> current, int index, Vector<Vector<int> > & bins)

{

if (index == requests.size())

{

if(sum(current,requests) <= stockLength && sum(current, requests)>0 )

        {
                bins.add(current);
            //  printBins(current,requests);
            }
            return ;
        }
        else
        {

        getBins(requests, current, index+1 , bins);
                current.add(index);
            getBins(requests, current, index+1 , bins);
        }
}

Ответы [ 5 ]

5 голосов
/ 29 ноября 2011

Алгоритм динамического программирования - O (n ^ {2k}), где k - количество различных элементов, а n - общее количество элементов. Это может быть очень медленным независимо от реализации. Как правило, при решении NP-сложной задачи эвристики требуются для скорости.

Я предлагаю вам рассмотреть уменьшение высоты при следующей подгонке (NFDH) и уменьшение высоты при первой подгонке (FFDH) от Coffman et al. Они 2-оптимальны и 17/10-оптимальны соответственно и работают за O (n log n) времени.

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

Рекомендации :

Оуэн Казер, Даниэль Лемир, Рисование в облаке тегов: алгоритмы визуализации в облаке , Маркировка и метаданные для организации социальной информации (WWW 2007), 2007. (См. Раздел 5.1 для обсуждения по теме.)

E. Г. Коффман-младший, М. Р. Гарей, Д. С. Джонсон и Р. Е. Тарьян. Границы производительности для ориентированных на уровень двумерных алгоритмов упаковки. SIAM J. Comput., 9 (4): 808–826, 1980.

1 голос
/ 03 апреля 2014

В вашем случае: размер ячейки = 30, общее количество предметов = 27, требуется как минимум 3 ячейки. Вы можете попробовать сначала уменьшиться, и это работает!

Больше способов улучшить: с 3 мусорными ведрами и 27 единицами размера у вас останется 3 единицы пространства. Это означает, что вы можете игнорировать элемент размером 1; если вы поместите остальные в 3 ячейки, они будут где-то помещаться. Это оставляет вам 26 единиц размера. Это означает, что в одной корзине будет по крайней мере два пустых блока. Если у вас есть предметы размером 2, вы также можете их игнорировать, потому что они подойдут. Если у вас было два предмета размером 2, вы также можете игнорировать предметы размером 3.

У вас есть два предмета размером 7 + 3, который точно соответствует размеру корзины. Всегда есть оптимальное решение, когда эти два находятся в одной корзине: если бы «7» были с другими предметами, их размер был бы 3 или меньше, так что вы могли бы поменять их местами с «3», если они находятся в другой корзине.

Другой метод: если у вас есть k элементов> = размер бина / 2 (на данный момент у вас не может быть двух элементов, равных размеру бина / 2), тогда вам нужно k бинов. Это может увеличить минимальное количество бинов, которое вы оценили изначально, что, в свою очередь, увеличивает гарантированное пустое пространство во всех бинах, что увеличивает минимальный размер оставшегося пространства в одном бине. Если для j = 1, 2, ..., k вы можете разместить всех элементов с ними в j корзинах, которые могут поместиться в одну и ту же корзину, то это оптимально. Например, если у вас есть размеры 8, 1, 1, но нет размера 2, тогда 8 + 1 + 1 в корзине будет оптимальным. Поскольку у вас осталось 8 + 4 + 4, а с 8 ничего не подходит, оптимальным будет только «8» в его корзине. (Если бы у вас были предметы размером 8, 8, 8, 2, 1, 1, 1 и ничего больше размера 2, оптимально было бы упаковать их в три корзины).

Можно попробовать еще больше вещей, если у вас есть большие предметы: если у вас есть крупный предмет, и самый крупный предмет, который ему подходит, такой же большой или больше, чем любая комбинация предметов, которая подходит, то объединение их является оптимальным. Если места больше, это можно повторить.

Таким образом, в целом, немного размышлений уменьшило проблему, поместив два элемента размером 4, 4 в один или несколько контейнеров. С большими проблемами, каждый немного помогает.

1 голос
/ 30 ноября 2011

Но если увеличить размер моего массива до более чем 6 элементов, это становится чрезвычайно медленным - для решения массива требуется около 25 секунд содержащий 8 элементов Можете ли вы сказать мне, если что-то не так с алгоритм?

Это нормально с грубой силой. Грубая сила вообще не масштабируется.

0 голосов
/ 03 апреля 2014

После того, как вы сделаете все возможное, чтобы уменьшить проблему, у вас остаётся проблема с размещением n элементов в k корзин, если это возможно, в k + 1 корзин в противном случае, или в k + 2 корзин и т.д.вы знаете, что у вас будет больше пустого пространства в оптимальном решении k + 1 корзин, что может позволить удалить больше мелких предметов, так что это первое, что нужно сделать.

Затем вы попробуете несколько простых методов: сначала подгонка по убыванию, затем подгонка по убыванию.Я попробовал достаточно быстрый вариант спуска по первому соответствию: пока подходят два самых больших элемента, добавьте самый большой элемент.В противном случае найдите один элемент или наибольшую комбинацию из двух подходящих элементов и добавьте один элемент или большее из этой комбинации.Если какой-либо из этих алгоритмов помещает ваши элементы в k корзин, вы решили проблему.

И в конце концов вам понадобится грубая сила.Вы можете решить: пытаетесь ли вы поместить все в k корзин, или вы пытаетесь доказать, что это невозможно?У вас будет свободное пространство для игры.Скажем, 10 корзин размером 100 и предметы общего размера 936, которые оставят вам 64 единицы пустого пространства.Если вы положите в свой первый ящик только предметы размером 80, то 20 из ваших 64 юнитов уже исчезнут, что затруднит поиск решения оттуда.Таким образом, вы не пробуете вещи в случайном порядке.Сначала вы пробуете комбинации для первого бина, которые заполняют его полностью или почти полностью.Поскольку мелкие предметы облегчают заполнение контейнеров полностью, вы стараетесь не использовать их в первых корзинах, а оставляете их на потом, когда у вас меньше выбора.И когда вы нашли предметы, которые нужно положить в корзину, попробуйте один из простых алгоритмов, чтобы увидеть, смогут ли они его закончить.Например, если при первом подходе по убыванию поместите 90 единиц в первый бункер, и вам только что удалось поместить туда 99 единиц, вполне возможно, что этого улучшения достаточно, чтобы уместить все.

С другой стороны, если места очень мало (например, 10 лотков, общий размер элемента 995), вы можете доказать, что подобрать элементы невозможно.Вам не нужно заботиться об оптимизации алгоритма, чтобы быстро найти решение, потому что вам нужно попробовать все комбинации, чтобы убедиться, что они не работают.Очевидно, что вам нужно с этими числами разместить не менее 95 единиц в первом бункере и т. Д .;это может облегчить быстрое исключение решений.Если вы доказали, что k бинов недостижимы, то k + 1 бинов должно быть намного более легкой целью.

0 голосов
/ 30 ноября 2011

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

...