Bin Packing Динамическое программирование Вопрос - PullRequest
10 голосов
/ 19 апреля 2011

У вас есть n1 предметов размером s1, n2 предметов размера s2 и n3 предметов размера s3. Вы хотели бы упаковать все эти предметы в контейнеры емкостью C, чтобы общее количество используемых контейнеров было минимальным.

Как мы можем достичь решения, используя минимальное количество корзин? Жадность точно не работает.

Ответы [ 8 ]

6 голосов
/ 19 апреля 2011

Это не глупый вопрос, ИМО.

Как известно, упаковка бункеров в целом является NP-Complete.

Но в вашем случае упаковка бинов с фиксированным числом весов объектов - этоИнтересный вариант.

В следующей статье утверждается, что алгоритм полиномиального времени поставляется с 1 из оптимальных: http://linkinghub.elsevier.com/retrieve/pii/S0377221706004310, когда вы разрешаете 3 разных размера.(Предостережение: я иду только по абстракции).

Так что я предполагаю, что эта версия тоже NP-Hard, и алгоритм Greedy, скорее всего, не будет работать.Не уверен в динамическом программировании (упаковка бина строго NP-Complete).

Надеюсь, это поможет.

2 голосов
/ 14 августа 2012

Это можно сделать за O(n1*n2*n3) ...

Допустим, f(i,j,k) - это минимум. бункеров, которые должны соответствовать i, j и k элементы размером s1, s2, s3 соответственно ..

Примечание : C - вместимость бункера

f(i,j,k) будет содержать 2 вида информации:

а) (The min no. of bins that are currently required) - 1. Скажем, собственность B1.

b) Текущий размер последней ячейки, доступной для дальнейшей подачи. Скажем, свойство B2 .. где 0 < B2 <= C

Следовательно, повторение будет:

f(i,j,k)([B1],[B2]) =
  min 
 { 
    f(i-1, j, k)( [B1] + [B2 + S1]/(C+1) , [B2 + S1] <=C ? [B2 + S1] : [B2 + S1 - C]) ,
    f(i, j-1, k)( [B1] + [B2 + S2]/(C+1) , [B2 + S2] <=C ? [B2 + S2] : [B2 + S2 - C]) ,
    f(i, j, k-1)( [B1] + [B2 + S3]/(C+1) , [B2 + S3] <=C ? [B2 + S3] : [B2 + S3 - C])
 }

Минимум нет. бункеров требуется: 1 + f(n1, n2, n3)[B1]

2 голосов
/ 20 апреля 2011

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

Я включил реализацию, которая для 3 разных размеров будет O(n1 * n2 * n3 * (C/s2) * (C/s3) * ((n1*s1 + n2*s2 + n3*s3)/C)) с довольно дерьмовой константой. (Эта цифра предоставлена ​​тем фактом, что у нас число различных шаблонов доступности равно O(n1 * n2 * n3), и для каждого мы генерируем O((C/s2) * (C/s3)) возможных следующих лотков, для каждого из которых мы должны работать с набором лотков, чьи размер O((n1*s1 + n2*s2 + n3*s3)/C)). Ряд рутинных оптимизаций может значительно ускорить эту программу.)

#! /usr/bin/python
import heapq

def min_bins(bin_size, sizes, counts):
    available = zip(sizes, counts)
    available.sort(reverse=True)
    seen = set([])
    upcoming = [(0, available, [])]
    while 0 < len(upcoming):
        (n, available, bins) = heapq.heappop(upcoming)
        for (bin, left) in bin_packing_and_left(bin_size, available):
            new_bins = bins + [bin]
            if 0 == len(left):
                return new_bins
            elif left not in seen:
                heapq.heappush(upcoming, (n+1, left, new_bins))
                seen.add(left)

def bin_packing_and_left(bin_size, available, top=True):
    if 0 == len(available):
        yield ((), ())
    else:
        (size, count) = available[0]
        available = available[1:]
        for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
            can_use = (bin_size - used) / size
            if count <= can_use:
                yield(((size, count),) + bin, left)
            elif 0 < can_use:
                yield(((size, can_use),) + bin,
                      ((size, count - can_use),) + left)
            else:
                yield(bin, ((size, count),) + left)

def bin_packing_and_left_size(bin_size, available):
    if 0 == len(available):
        yield ((), (), 0)
    else:
        (size, count) = available[0]
        available = available[1:]
        for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
            for i in range(1 + min(count, (bin_size - used) / size)):
                if count == i:
                    yield(((size, count),) + bin, left, used + size * count)
                elif 0 < i:
                    yield(((size, i),) + bin,
                          ((size, count - i),) + left,
                          used + size * i)
                else:
                    yield(bin, ((size, count),) + left, used)

answer = min_bins(23, (2, 3, 5), (20, 30, 40))
print len(answer)
print answer
0 голосов
/ 01 октября 2012

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

Предположим, что элементы размером S1, b элементовразмера S2, c элементов размера S3 - это максимальное количество элементов, которые я могу разместить в одном бункере.Таким образом, максимальный размер, который я могу поместить в одну корзину, равен K = a * S1 + b * S2 + c * S3. Поэтому ответ будет (n1 * S1 + n2 * s2 + n3 * s3) / K + (n1 * S1+ n2 * s2 + n3 * s3)% K нет ячеек.

Найти K проще, чем стандартная задача о ранце. Если я предполагаю, что все оптимальные значения до i существуют 1 <= i <= C.оптимальное значение i + 1 может быть записано рекурсивно как </p>

M(i+1) = max(M(i),M(i-S1)+S1,M(i-S2)+S2,M(i-S3)+S3).
0 голосов
/ 12 ноября 2011

Вот эскиз алгоритма DP для этого.

Рекурсивное отношение: мы возвращаемся к B(i, j, k), минимальному количеству бункеров емкости C, необходимому для упаковки i предметов размером s1, j предметовразмер s2 и k предметов размером s3.Отношение:

B(i, j, k) = min {B (x,y,z) , B(i-x, j-y, k-z)} 
where 0<=x<=i; 
0<=y<=j; 
0<=z<=k

, где хотя бы один из x, y или z должен быть больше 0 и один из x, y или zдолжно быть меньше i, j или k соответственно.

Время работы: B - это размер O (n3), а для вычисления каждого элемента B требуется время O (n3) для общего времениO (n6).

0 голосов
/ 20 апреля 2011

Минимальное количество бункеров при условии отличной упаковки будет B = ceiling( sum(n(i)*s(i) for i in 1..3) / C )

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

0 голосов
/ 20 апреля 2011

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

Однако я не уверен, так как никогда не изучал эту проблему глубоко. Тем не менее, есть книга под названием «Проблемы с ранцами», в которой представлены формулировки и алгоритмы, в том числе проблемы упаковки бинов. Нетрудно найти его в формате PDF в Интернете.

Надеюсь, это поможет. Удачи.

0 голосов
/ 19 апреля 2011

Если вы можете свести свою проблему к 1d упаковке, вы хотите использовать жадный алгоритм, используемый здесь: http://www.developerfusion.com/article/5540/bin-packing

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