Ограничения заказа в оптимизации

У меня есть набор из множества (10000+) предметов, из которых мне нужно выбрать ровно 20 предметов. Я могу выбрать каждый элемент только один раз. У моих предметов есть прибыль и стоимость, а также несколько логических свойств (например, цвет). Мне нужно вывести результаты в определенном порядке: в частности, мне нужно, чтобы первый и третий элементы были синими, а второй и четвертый элементы были красными.

Каждый элемент представлен в виде кортежа:

item = ('item name', cost, profit, is_blue, is_red)

Например

vase = ['Ming Vase', 1000, 10000, 0, 1]

plate = ['China Plate', 10, 5, 1, 0]

а общий набор элементов представляет собой список списков:

items = [item1, item2, ..., itemN].

Моя прибыль и расходы также перечислены:

profits = [x[2] for x in items]
costs = [x[1] for x in items]

Для каждого выбранного элемента оно должно иметь минимальное значение, и минимум 5 элементов должны иметь флаг свойства (is_blue), установленный на 1.

Я хочу выбрать 20 самых дешевых предметов с наивысшим значением, так, чтобы у 5 из них флаг is_blue был установлен в 1, а первый и третий элементы были синими (и т. Д.).

У меня возникли проблемы с формулировкой этого с помощью инструментов Google OR.

from ortools.linear_solver import pywraplp

solver = pywraplp.Solver('SolveAssignmentProblemMIP',
                       pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)

x = {}

for i in range(MAX_ITEMS):
    x[i] = solver.BoolVar('x[%s]' % (i))

#Define the constraints 
total_chosen = 20
solver.Add(solver.Sum([x[i] for i in range(MAX_ITEMS)]) == total_chosen)

blues = [x[3] for x in items]
solver.Add(solver.Sum([blues[i] * x[i] for i in . 

диапазон (MAX_ITEMS)])> = 5)

max_cost = 5.0

for i in range(MAX_ITEMS):
    solver.Add(x[i] * cost[i] <= max_cost)

solver.Maximize(solver.Sum([profits[i] * x[i] for i in range(total_chosen)]))
sol = solver.Solve()

Я могу получить набор предметов, который выбрал:

for i in range(MAX_ITEMS):
    if x[i].solution_value() > 0:
        print(item[i].item_name)

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

Любая помощь в формулировании ограничений и целей была бы действительно полезной. Спасибо!


person Tom Kealy    schedule 06.11.2018    source источник
comment
Почему вас волнует, что первый синий? У вас будет как минимум 5 синих предметов, поэтому просто измените порядок решения так, чтобы 1-й и 3-й элементы были синими.   -  person juvian    schedule 06.11.2018


Ответы (1)


Вместо того, чтобы выражать выбранные элементы с помощью BoolVar, рассмотрите возможность создания списка из 20 IntVar с доменом 0..MAX_ITEMS. Оттуда должно быть довольно легко сделать что-то вроде этого:

solver.Add(chosens[0].IndexOf(all_items)[3] == 1)
solver.Add(chosens[2].IndexOf(all_items)[3] == 1)

selectedns [i] .IndexOf (all_items) просто означает all_items [IndexOfChosen], I.E: какой бы элемент ни был выбран для I-го места. Если вы придерживаетесь этого подхода, не забудьте MakeAllDifferent!

person Burak    schedule 19.11.2018
comment
@Tom Kealy Также рассмотрите возможность использования cp_sat, поскольку он более яркий, лучший и в большинстве случаев быстрее. - person Burak; 19.11.2018