Разделить и вырезать - метод комбинаторной оптимизации для решение целочисленных линейных программ (ILP), то есть задач линейного программирования (LP), в которых некоторые или все неизвестные ограничены целыми значениями. Разделение и вырезание включает в себя выполнение алгоритма ветвей и границ и использование плоскостей разреза для усиления релаксации линейного программирования. Обратите внимание, что если сокращения используются только для ужесточения начального ослабления LP, алгоритм называется разрезать и ветвиться.
Это описание предполагает, что ILP является проблемой максимизации.
Метод решает линейную программу без целочисленного ограничения с использованием обычного симплексного алгоритма. Когда получено оптимальное решение, и это решение имеет нецелочисленное значение для переменной, которая должна быть целой, можно использовать алгоритм плоскости отсечения для поиска дополнительных линейных ограничений, которым удовлетворяют все допустимых целых точек, но нарушенных текущим дробным решением. Эти неравенства могут быть добавлены к линейной программе, так что ее разрешение приведет к другому решению, которое, будем надеяться, будет «менее дробным».
На этом этапе запускается часть алгоритма ветвления и привязки. Проблема разбита на несколько (обычно две) версии. Затем новые линейные программы решаются симплексным методом, и процесс повторяется. В процессе ветвей и границ нецелые решения LP-релаксации служат в качестве оценок сверху, а интегральные решения - в качестве оценок снизу. Узел может быть сокращен, если верхняя граница ниже существующей нижней границы. Кроме того, при решении LP-релаксации могут быть сгенерированы дополнительные плоскости сечения, которые могут быть либо глобальными разрезами, т. Е. Действительными для всех возможных целочисленных решений, либо локальными разрезами, что означает, что они удовлетворяются всеми решениями, выполняющими боковые ограничения из текущего считается ветвлением и связанным поддеревом.
Алгоритм кратко описан ниже.
В C ++ -подобный псевдокод это можно было бы записать:
1 // Псевдокод решения ветвления и отсечения ILP, предполагая, что цель - максимизировать 2 ILP_solution branch_and_cut_ILP (IntegerLinearProgram initial_problem) {3 очередь active_list; // L, выше 4 active_list.enqueue (initial_problem); // шаг 1 5 // шаг 2 6 ILP_solution optim_solution; // это будет содержать x * больше 7 double best_objective = -std :: numeric_limits:: infinity; // сохранит v * выше 8 while (! active_list.empty ()) {// шаг 3 выше 9 LinearProgram curr_prob = active_list.dequeue (); // шаг 3.1 10 do {// шаги 3.2–3.7 11 RelaxedLinearProgram relaxed_prob = LP_relax (curr_prob); // шаг 3.2 12 LP_solution curr_relaxed_soln = LP_solve (relaxed_prob); // это x больше 13 bool cut_planes_found = false; 14 if (! Curr_relaxed_soln.is_feasible ()) {// шаг 3.3 15 continue; // пробуем другое решение; продолжается на шаге 3 16} 17 double current_objective_value = curr_relaxed_soln.value (); // v выше 18 if (current_objective_value <= best_objective) { // step 3.4 19 continue; // try another solution; continues at step 3 20 } 21 if (curr_relaxed_soln.is_integer()) { // step 3.5 22 best_objective = current_objective_value; 23 optimal_solution = cast_as_ILP_solution(curr_relaxed_soln); 24 continue; // continues at step 3 25 } 26 // current relaxed solution isn't integral 27 if (hunting_for_cutting_planes) { // step 3.6 28 violated_cutting_planes = search_for_violated_cutting_planes(curr_relaxed_soln); 29 if (!violated_cutting_planes.empty()) { // step 3.6 30 cutting_planes_found = true; // will continue at step 3.2 31 for (autocutting_plane : violated_cutting_planes) { 32 active_list.enqueue(LP_relax(curr_prob, cutting_plane)); 33 } 34 continue; // continues at step 3.2 35 } 36 } 37 // step 3.7: either violated cutting planes not found, or we weren't looking for them 38 autobranched_problems = branch_partition(curr_prob); 39 for (autobranch : branched_problems) { 40 active_list.enqueue(branch); 41 } 42 continue; // continues at step 3 43 } while (hunting_for_cutting_planes /* parameter of the algorithm; see 3.6 */ 44 cutting_planes_found); 45 // end step 3.2 do-while loop 46 } // end step 3 while loop 47 return optimal_solution; // step 4 48 }
В приведенном выше псевдокоде функции LP_relax
, LP_solve
и branch_partition
, вызываемые как подпрограммы, должны быть предоставлены как применимые к Например, LP_solve
может вызывать симплекс-алгоритм. Стратегии ветвления для branch_partition
обсуждаются ниже.
Важным шагом в алгоритме ветвления и отсечения является шаг ветвления. На этом шаге можно использовать множество эвристик ветвления. Все описанные ниже стратегии ветвления включают так называемое ветвление по переменной. Ветвление по переменной включает выбор переменной с дробным значением, , в оптимальном решении текущей релаксации LP с последующим добавлением ограничений и
Существует также большое количество вариантов этих стратегий ветвления, например, использование сильного ветвления на ранней стадии когда ветвление по псевдозатратности относительно неинформативно, а затем переключение на ветвление по псевдозатратности происходит позже, когда имеется достаточно истории ветвлений, чтобы псевдозатраты были информативными.