Вы решаете вариант задачи коммивояжера. В частности, то, что вы получаете, называется субтуром, который представляет собой замкнутый путь, который включает меньше, чем все узлы (в вашем случае магазины).
Для данного набора узлов существует экспоненциальное количество подтуров. Существует огромное количество литературы, посвященной ограничениям исключения субтура. К счастью, для небольших проблем на практике мы можем обойтись добавлением ограничений исключения субтур по мере необходимости.
Отборочный тур
Вот идея, как исключить подтур S, который включает s магазинов (s ‹num_stores):
На английском языке: мы начинаем с разделения набора узлов (магазинов) на две группы S и T. Пусть S будет набором магазинов в субтур. Пусть T будет набором магазинов вне S, то есть всех остальных магазинов. Мы хотим разорвать однопетлевый путь, в котором участвуют только магазины в S.
Псевдокод
Do while:
Solve the current problem
If you don't find any subtours, you are done. Exit.
If there are subtours, add the subtour elimination constraints (see details below)
Continue
Реализация набора ограничений для исключения текущего субтура
Для каждого субтура («острова») вы должны сначала создать набор из shops_in_subtour
. Все остальные узлы (магазины) входят в другой набор (T) shops_not_in_subtour
Добавьте в набор ограничений следующее:
forall(s in shops_in_subtour)
forall(t in shops_not_in_subtour)
sum y[s,t] > = 1; // at least one edge must leave S and go to T
sum y[t,s] > = 1; // at least one edge must enter the set S from T
Если ваша проблема небольшая, вы увидите, что добавления нескольких из этих наборов ограничений будет достаточно. Надеюсь, это поможет вам двигаться вперед.
Обновление на основе дополнительного вопроса OP
Как определить субтуры
Вы проверите наличие субтур вне CPLEX / Solver
Идея на английском языке: вы начинаете с исходного магазина и идете по пути, отслеживая каждый visited
магазин. Если вы вернетесь к исходной точке, и все еще останутся некоторые двоичные переменные Y, у вас есть один или несколько субтур. (Технически вы можете начать с любого магазина, но начать с одного легче понять.)
Initialize visited_shop = NULL;
Find the Yij that is 1. (Starting edge for the path)
Do while (There are more Y variables = 1 remaining)
Add the destination of the new binary variable to list of visited_shops
Check if you are done (are you back at shop 1):
if Yes:
If no more binary variables left, you are done. Exit.
If there are some more non-zero binary variables, subtour detected
if No:
pick the next Y variable whose origin is current Y_variable's destination
Continue
person
Ram Narasimhan
schedule
25.12.2013