Комбинаторная оптимизация с несколькими ограничениями

У меня есть проблема, связанная с оптимизацией снаряжения в игре, но я упрощу ее на следующем примере:

  • Допустим, у меня есть 4 сумки.
  • У меня есть набор разных предметов, 4 вида.
  • У каждого предмета свой вес и цена.
  • Каждая сумка предназначена для одного вида вещей, 4 сумки - 4 вида.


Я хочу максимально увеличить цену, которую ношу во всех сумках, но у меня есть следующие ограничения:

  1. Каждая сумка вмещает не более 6 предметов. Он тоже может быть пустым.
  2. Общий вес всех 4 мешков не должен превышать 700 кг.
  3. Каждый мешок имеет минимальное значение веса, даже если он пустой, он будет считаться 50 кг (мешок с 1 предметом весом 25 кг будет по-прежнему считаться как 50 кг, мешок с 1 предметом весом 51 кг будет считаться как 51 кг).

Диапазон количества элементов составляет 200 ~ 300, а при максимальном количестве элементов 6 * 4 = 24, которые могут быть выбраны, перебор невозможен.

Есть и другие факторы, но они выходят за рамки комбинаторной проблемы и могут быть решены простым программированием



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

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

Обновлять


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

Кто-нибудь знает хороший подход к этому?

Обновление 2


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

# Size of knapsack
param s;
# Total of items
param t;
# Type of items
set Z;
# Min bag
param m;

# Items: index, size, profit, count, type
set I, dimen 5;

# Indices
set J := setof{(i,s,p,o,z) in I} i;

# Assignment
var a{J}, binary;

#maximize profit
maximize obj :
  sum{(i,s,p,o,z) in I} p*a[i];

/*s.t. size :
  sum{(i,s,p,o,z) in I} s*a[i] <= c;*/

#constraint of total weight, but with the min value for each bag
#the min function doesn't work, it says argument for min has invalid type
#something about it not being a linear function
s.t. size :
  sum{zz in Z} ( 
    min(m, sum{(i,s,p,o,z) in I: zz=z} (s*a[i]) )
  ) <= c;

#constraint of number of items in each bag, i put an extra count number
#in the set so i could sum it and make it a constraint
s.t. count{zz in Z}:
  sum{(i,s,p,o,z) in I: zz=z} o*a[i] <= t;

solve;

printf "The bag contains:\n";
printf {(i,s,p,o,z) in I: a[i] == 1} " %i", i;
printf "\n";

data;

#set of type of items
set Z := 1 2 3 4;

# Total weight limit
param c := 100;
# Only 2 items per bag
param t := 2;
# Min bag value, if the bag weights less than it, then it counts as this value
param M := 10;

# Items: index, size, profit, count, type
set I :=
  1 10 10 1 1 
  2 10 10 1 1
  3 15 45 1 2
  4 20 20 1 2
  5 20 20 1 3
  6 24 24 1 3
  7 24 25 1 4
  8 50 50 1 4;

end;

Примечание: я использовал здесь разные значения, чтобы они были небольшими.

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

(не могу публиковать изображения)

min (a, b) = (a + b- abs (ab)) / 2

но я тоже не могу использовать функцию абс.

Может ли кто-нибудь указать мне в правильном направлении по этому поводу.


person dpaladin    schedule 12.12.2015    source источник


Ответы (3)


Вы можете сформулировать свою проблему как целочисленную программу 0-1 и решить ее с помощью GLPK или другого решателя линейного программирования (glpk предоставляется бесплатно). Единственный вопрос: вы берете пустые сумки? Позволять

i = {1,2,3,4} -- set of item types
j -- set of items
x_ij = {0,1} -- decision variable for jth item of ith type
w_ij and p_ij -- weights and profits

max sum_ij p_ij*x_ij

subject to:
sum_j x_ij <= 6 for all i  // at most 6 items in a bag
// if you need empty bags:
sum_ij w_ij*x_ij + 4*50 <= 700 kg  // total weight

x_ij = {0,1} for all i and j.

если вам не нужны пустые пакеты, то рецептура усложняется

max sum_ij p_ij*x_ij

subject to:
sum_j x_ij <= 6    for all i  // at most 6 items in a bag
sum_ij w_ij*x_ij + 50*(sum_i y_i) <= 700 kg  // total weight
y_i <= sum_j x_ij    for all i  
N*y_i >= sum_j x_ij    for all i  // N -- total number of items of ith type, 
                                  // fixed value, not a variable; e.g., 
                                  // you have 10 items of each kind then N=10

y_i = {0,1} for all i
x_ij = {0,1} for all i and j.

Если вам нужно решить программу один раз, я предлагаю написать файл cplex .lp http://www-01.ibm.com/support/knowledgecenter/SS9UKU_12.4.0/com.ibm.cplex.zos.help/FileFormats/topics/LP.html и решите эту проблему с помощью glpsolve; в противном случае используйте вызываемые библиотеки c ++ или python glpk.

Обновление 1:

Можно линеаризовать ограничение min{50, sum_i x_i*w_i} в два этапа. Для простоты рассмотрим один рюкзак. Позволять

M -- the total possible weight (sum up all input items' weights)
y={0,1} -- when sum_i x_i*w_i >= 50 y=1, otherwise y=0

min{50, sum_i x_i*w_i} <= 100    is equivalent to
(0): (1-y)*50 + y*(sum_i x_i*w_i) <= 100
(1): My >= sum_i x_i*w_i - 50
(2): M(1-y) >= 50 - sum_i x_i*w_i

это немного необычно, но правильно. Действительно, когда sum_i x_i*w_i >= 50 решатель должен установить y в 1 ограничением (1), в то же время (2) просто 0 >= 50-sum_i x_i*w_i <= 0, т.е. является избыточным; когда sum_i x_i*w_i < 50, y = 0 на (2), и теперь (1) является избыточным.

Следующим шагом является линеаризация второго члена в (0). Пусть z_i = {0,1}, это будет y*x_i термин. Обратите внимание, что y*x_i равно 1 только тогда, когда оба члена равны 1, в противном случае - 0. Следовательно,

y*(sum_i x_i*w_i)  is equivalent to

sum_i z_i*w_i
2*z_i <= x_i + y,  for all i
z_i >= x_i + y - 1,  for all i

как и раньше, легко проверить, что z_i = 1, только если x_i = y = 1, в противном случае - 0.

После линеаризации ваше ограничение выглядит следующим образом:

(0): (1-y)*50 + (sum_i z_i*w_i) <= 100

(1): My >= sum_i x_i*w_i - 50
(2): M(1-y) >= 50 - sum_i x_i*w_i

(3): 2*z_i <= x_i + y,  for all i
(4): z_i >= x_i + y - 1,  for all i

 y = {0,1}, z_i = {0,1}
person serge_k    schedule 13.12.2015
comment
Спасибо, что разместили эту замечательную программу. Мне проще понять с точки зрения программирования. Я смоделировал в нем проблему, и она почти решена, у меня осталась одна последняя проблема. Я не был достаточно ясен с ограничением 50 кг мин, я имел в виду следующее: допустим, мы закончили с 1 предметом в мешке 1 с весом 25 кг, этот мешок будет считаться 50 кг. Так что это min( 50, sum{size in set} size*a[i] ), но я не могу этого сделать. Я обновлю. - person dpaladin; 14.12.2015
comment
Я обновил свой пост с некоторыми хитростями, как справиться с такими ограничениями. Вам нужно ввести дополнительные переменные, но с этим ничего не поделаешь, это побочный эффект линеаризации. В настоящее время решатели LP очень мощные, я смог решить LP со 100 000 переменных на своем ноутбуке всего за несколько минут. - person serge_k; 14.12.2015
comment
Наконец-то я смог разобраться в этом (у меня не было много времени). Я не понимаю некоторых из этих ограничений, но я заставил их работать для нескольких пакетов, и теперь моя программа работает идеально, я опубликую ее позже. Большое тебе спасибо. Можете ли вы порекомендовать внимательно прочитать об этих трюках? - person dpaladin; 21.12.2015
comment
когда я изучал LP, я использовал Bertsimas Introduction to Linear Optimization mit.edu/~dbertsim/books.html, но технически подойдет любая лекция по линейному программированию или линейной оптимизации, моделирование - стандартная тема. Я уверен, что в Интернете можно найти хорошие слайды или открытый курс. - person serge_k; 22.12.2015

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

W_j >= 50  for all j
W_j >= sum_i w_i * X_ij for all j
sum_j W_j <= 700

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

Удачи :)

person Koen Peters    schedule 14.12.2015

Если вы ищете точный оптимальный ответ, эта проблема является NP-полной, однако я заметил, что вы описываете очень небольшой набор проблем.

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

Если вместо этого в вашем примере вы намеревались обрисовать в общих чертах только описание проблемы, а ваш набор реальных проблем на самом деле «большой», грубая сила не сработает, так как время выполнения будет экспоненциально увеличиваться с увеличением количества элементов. Вот довольно старая статья по этой проблеме.

Интересно отметить, что вы можете преобразовать свои ограничения в числовые «Взыскать» и использовать неограниченные методы оптимизации, немного упростив вашу задачу.

Алгоритмы, гарантирующие оптимальное решение, по-прежнему нуждаются в эвристике, быстро отсекающей плохие / невыполнимые и "доминирующие" решения.

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

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

person Michele Giuseppe Fadda    schedule 13.12.2015
comment
Грубая сила была моим первым вариантом, пока я не сделал некоторые вычисления. С 200+ возможными предметами, 4 мешка и максимум 6 предметов в каждом C (200,24) = 6422888012237563751246901602700 Извините за то, что не сказал этого в сообщении. И да, мне нужно точное решение, я пробовал читать несколько книг, но я не понимаю некоторых символов, похоже, мне нужно прочитать всю теорию. - person dpaladin; 14.12.2015