Логистические производственно-транспортные системы - УрГУПС

Курс лекций и лабораторных работ

Лекция 2.7. Транспортная задача: линейное программирование

Содержание


Постановка транспортной задачи

Транспортная задача — задача оптимизации перевозок грузов от поставщиков к потребителям с минимальными затратами при соблюдении ограничений по запасам и спросу.

Это классическая задача линейного программирования (ЛП), имеющая, однако, специальную структуру, которая позволяет решать её эффективнее общего симплекс-метода — табличными алгоритмами (метод потенциалов) и специализированными решателями (min-cost flow).

Исходные данные

Поставщики:

Потребители:

Стоимости перевозки:

Данные сводятся в таблицу транспортных затрат — основной рабочий документ метода:

  П1 П2 … Пn Запас
С1 $c_{11}$ $c_{12}$ … $c_{1n}$ $A_1$
С2 $c_{21}$ $c_{22}$ … $c_{2n}$ $A_2$
… … … … … …
Сm $c_{m1}$ $c_{m2}$ … $c_{mn}$ $A_m$
Спрос $B_1$ $B_2$ … $B_n$ —

Содержательная интерпретация

В логистике под «поставщиком» и «потребителем» могут пониматься объекты самой разной природы:

Постановка Поставщики Потребители Единица $x_{ij}$
Перевозка со складов в магазины Распределительные центры Розничные точки Тонны, паллеты
Внутризаводские перевозки Цеха-изготовители Цеха-потребители полуфабрикатов Единицы деталей
Порожний пробег вагонов Станции с избытком вагонов Станции с дефицитом Вагоны
Назначение поставщиков потребителям Поставщики материалов Производственные переделы Объём поставки
Размещение заказов Заводы-изготовители Региональные склады Единицы продукции

Пример

Данные:

Поставщик \ Потребитель П1 П2 П3 Запас
С1 5 8 3 100
С2 4 6 7 150
С3 9 5 4 200
Спрос 120 180 150 —

Проверка баланса: $100 + 150 + 200 = 450$; $120 + 180 + 150 = 450$ — модель закрытая.

Вопрос: Сколько и куда перевозить для минимизации затрат?

Транспортная задача как частный случай линейного программирования

Общая задача ЛП: найти $\min c^T x$ при ограничениях $Ax \leq b$, $x \geq 0$, решаемую симплекс-методом. Транспортная задача отличается тем, что:

Эти свойства делают возможным простой табличный алгоритм решения без построения симплекс-таблиц.


Математическая модель

Целевая функция

Минимизация совокупных затрат:

\[min \sum_{i=1}^{m}\sum_{j=1}^{n} C_{ij} \cdot x_{ij}\]

Где:

Ограничения

По запасам поставщиков:

\[\sum_{j=1}^{n} x_{ij} \leq A_i, \quad i = 1, ..., m\]

По спросу потребителей:

\[\sum_{i=1}^{m} x_{ij} \geq B_j, \quad j = 1, ..., n\]

Неотрицательность:

\[x_{ij} \geq 0\]

В закрытой модели неравенства обращаются в равенства: весь запас вывозится, весь спрос удовлетворяется.

Балансовое условие

Закрытая модель (спрос = предложение):

\[\sum_{i=1}^{m} A_i = \sum_{j=1}^{n} B_j\]

Открытая модель (требуется балансировка):

Перевозки фиктивному участнику интерпретируются как невыполненные (оставленный на складе запас или неудовлетворённый спрос) — их величина в оптимальном плане показывает, какие реальные перевозки окажутся «лишними» или «недостающими».

Открытая модель: балансировка фиктивным участником

Пример. Пусть запасы уменьшились: $A_1 = 50$, $A_2 = 60$, $A_3 = 70$ (итого 180), а спрос прежний — 200. Дефицит: $200 - 180 = 20$ ед. Вводим фиктивного поставщика С4 с запасом 20 и нулевыми тарифами:

С \ П П1 П2 П3 П4 Запас
С1 2 4 8 7 50
С2 5 3 6 9 60
С3 8 7 4 2 70
С4 (фикт.) 0 0 0 0 20
Спрос 40 50 60 50 200

Решение методом минимального элемента (нулевые тарифы выбираются первыми):

  1. Минимум 0 (С4–П1): $x_{41} = \min(20, 40) = 20$ → С4 исчерпан, П1 осталось 20;
  2. Минимум 2 (С1–П1): $x_{11} = 20$ → П1 удовлетворён, С1 осталось 30;
  3. Минимум 2 (С3–П4): $x_{34} = 50$ → П4 удовлетворён, С3 осталось 20;
  4. Минимум 3 (С2–П2): $x_{22} = 50$ → П2 удовлетворён, С2 осталось 10;
  5. Минимум 4 (С3–П3): $x_{33} = 20$ → С3 исчерпан, П3 осталось 40;
  6. Минимум 6 (С2–П3): $x_{23} = 10$ → С2 исчерпан, П3 осталось 30;
  7. Минимум 8 (С1–П3): $x_{13} = 30$ → всё распределено.

Интерпретация: $x_{41} = 20$ означает, что потребитель П1 недополучит 20 единиц (его потребность 40 удовлетворена лишь на 20 со склада С1). Реальные транспортные затраты: $20 \cdot 2 + 50 \cdot 2 + 50 \cdot 3 + 20 \cdot 4 + 10 \cdot 6 + 30 \cdot 8 = 40 + 100 + 150 + 80 + 60 + 240 = 670$ руб.


Свойства транспортной задачи

Ранг системы ограничений и базис

Система из $m + n$ уравнений баланса линейно зависима: сумма уравнений по строкам тождественно равна сумме уравнений по столбцам (обе равны общему объёму перевозок). Поэтому ранг системы равен $m + n - 1$ — столько же должно быть ненулевых (базисных) клеток в опорном плане.

Правило контроля: после построения начального плана сосчитайте занятые клетки. Если их ровно $m + n - 1$ — план невырожденный. Если меньше — план вырожденный, и для работы метода потенциалов одну из свободных клеток следует объявить базисной с нулевой поставкой.

Для примера 3×3 (раздел «Постановка»): $m + n - 1 = 3 + 3 - 1 = 5$ базисных клеток; для примера 3×4, решаемого ниже: $3 + 4 - 1 = 6$.

Опорный план и вырожденность

Опорный план — любой допустимый план перевозок (удовлетворяющий ограничениям) с $m + n - 1$ базисными клетками. Вырожденность возникает, когда число занятых клеток меньше $m + n - 1$ (например, когда на шаге распределения одновременно обнуляются и строка, и столбец).

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

Теорема (целочисленность): при целых запасах и спросе существует оптимальный план с целыми $x_{ij}$ — важное свойство для практики (грузы неделимы: контейнеры, вагоны, паллеты).


Методы построения начального плана

Сравнение методов

Метод Идея Качество начального плана Трудоёмкость
Северо-западный угол Заполнение с левого верхнего угла без учёта тарифов Низкое (далёк от оптимума) Минимальная
Минимальный элемент Сначала самые дешёвые клетки Хорошее (близок к оптимуму) Низкая
Метод Фогеля (аппроксимации) Учёт разницы двух минимальных тарифов в строке/столбце Наилучшее из эвристик Средняя
Двойственный метод (Йоффе) Оценка по минимумам строк и столбцов Высокое Средняя

Метод северо-западного угла

Алгоритм: начать с клетки (1,1), назначить $x_{11} = \min(A_1, B_1)$, исчерпанную строку/столбец исключить, перейти к следующей северо-западной клетке оставшейся подтаблицы.

Метод не учитывает стоимость и даёт худший начальный план, но прост и полезен для понимания структуры алгоритма. Для примера 3×3 из начала лекции он даёт план $x_{11} = 100$, $x_{21} = 20$, $x_{22} = 130$, $x_{32} = 50$, $x_{33} = 150$ с затратами $100 \cdot 5 + 20 \cdot 4 + 130 \cdot 6 + 50 \cdot 5 + 150 \cdot 4 = 500 + 80 + 780 + 250 + 600 = 2210$ руб. против 1970 руб. по методу минимального элемента — сразу на 12% дороже.

Метод минимального элемента: алгоритм

Шаг 1. Найти клетку с минимальной стоимостью $C_{ij}$ среди нераспределённых.

Шаг 2. Назначить максимальную перевозку:

\[x_{ij} = min(A_i, B_j)\]

Шаг 3. Скорректировать запасы и спрос:

Шаг 4. Исключить удовлетворённую строку или столбец (при одновременном обнулении исключается одно, второе остаётся с нулевым остатком).

Шаг 5. Повторять шаги 1–4 до полного распределения.

Шаг 6. Проверить число базисных клеток: должно быть $m + n - 1$.


Решение примера методом минимального элемента

Рассмотрим полную задачу 3×4 — поставка материалов с трёх складов АО «Ракета» (склад обеспечения, склад цеха микросборки, склад цеха агрегатов) четырём производственным участкам-потребителям.

Условие (закрытая модель):

С \ П П1 П2 П3 П4 Запас
С1 2 4 8 7 50
С2 5 3 6 9 60
С3 8 7 4 2 90
Спрос 40 50 60 50 200

Итерации распределения

Итерация 1. Минимальный тариф — $c_{11} = 2$ (С1–П1). Назначаем:

\[x_{11} = \min(50, 40) = 40\]

П1 удовлетворён (столбец исключаем), у С1 осталось $50 - 40 = 10$.

С \ П П1 П2 П3 П4 Остаток
С1 40 4 8 7 10
С2 × 3 6 9 60
С3 × 7 4 2 90
Остаток спроса — 50 60 50  

Итерация 2. Минимальный тариф среди доступных — $c_{34} = 2$ (С3–П4):

\[x_{34} = \min(90, 50) = 50\]

П4 удовлетворён (столбец исключаем), у С3 осталось $90 - 50 = 40$.

Итерация 3. Минимум — $c_{22} = 3$ (С2–П2):

\[x_{22} = \min(60, 50) = 50\]

П2 удовлетворён, у С2 осталось $60 - 50 = 10$.

Итерация 4. Минимум — $c_{33} = 4$ (С3–П3):

\[x_{33} = \min(40, 60) = 40\]

С3 исчерпан (строку исключаем), П3 осталось $60 - 40 = 20$.

Итерация 5. Минимум среди оставшихся (строки С1, С2; столбец П3) — $c_{23} = 6$ (С2–П3):

\[x_{23} = \min(10, 20) = 10\]

С2 исчерпан, П3 осталось $20 - 10 = 10$.

Итерация 6. Единственная доступная клетка — $c_{13} = 8$ (С1–П3):

\[x_{13} = \min(10, 10) = 10\]

Все запасы распределены, весь спрос удовлетворён.

Итоговый опорный план

С \ П П1 П2 П3 П4 Запас
С1 40 — 10 — 50
С2 — 50 10 — 60
С3 — — 40 50 90
Спрос 40 50 60 50 200

Проверка вырожденности: занятых клеток 6 = $m + n - 1 = 3 + 4 - 1 = 6$ — план невырожденный.

Затраты опорного плана:

\[F_0 = 40 \cdot 2 + 10 \cdot 8 + 50 \cdot 3 + 10 \cdot 6 + 40 \cdot 4 + 50 \cdot 2 = 80 + 80 + 150 + 60 + 160 + 100 = 630\ \text{руб.}\]

Справка. Для сравнения: метод северо-западного угла на тех же данных даёт план $x = {40, 10, 40, 20, 40, 50}$ (по клеткам С1П1, С1П2, С2П2, С2П3, С3П3, С3П4) с затратами $80 + 40 + 120 + 120 + 160 + 100 = 620$ руб. — случайно совпавшими с оптимумом. Это иллюстрирует важный принцип: начальный план может оказаться любым по качеству; только проверка методом потенциалов доказывает оптимальность.


Метод потенциалов

Теоретическая основа метода

Метод потенциалов — применение условия оптимальности двойственной задачи ЛП к транспортной задаче. Каждому поставщику $i$ сопоставляется потенциал $u_i$, каждому потребителю $j$ — потенциал $v_j$.

Условие оптимальности (теорема): опорный план оптимален тогда и только тогда, когда существуют потенциалы, удовлетворяющие системе:

Алгоритм проверки оптимальности

Шаг 1. Назначить потенциалы $u_i$ и $v_j$ так, чтобы для всех базисных клеток выполнялось $u_i + v_j = C_{ij}$ (система из $m + n - 1$ уравнений с $m + n$ неизвестными — одно значение задаётся произвольно).

Шаг 2. Принять $u_1 = 0$ и последовательно вычислить остальные потенциалы через базисные клетки.

Шаг 3. Вычислить оценки свободных клеток:

\[\Delta_{ij} = C_{ij} - (u_i + v_j)\]

Шаг 4. Проверить оптимальность:

Шаг 5. Для улучшающей клетки построить цикл перераспределения — замкнутую ломаную из горизонтальных и вертикальных отрезков, вершины которой лежат в базисных клетках (плюс вводимая клетка). Знаки в вершинах цикла чередуются: «+» во вводимой клетке, далее поочерёдно «−» и «+».

Шаг 6. Найти $\theta = \min{x_{ij}\ \ (i,j)\ \text{со знаком «−»}}$ и пересчитать план: $x_{ij} + \theta$ в плюсовых клетках, $x_{ij} - \theta$ в минусовых. Одна из минусовых клеток освобождается (становится свободной).

Шаг 7. Вернуться к шагу 1 до достижения оптимальности.

Итерация 1: проверка плана ММЕ

Расставим потенциалы по базисным клеткам плана $F_0 = 630$: $x_{11} = 40$, $x_{13} = 10$, $x_{22} = 50$, $x_{23} = 10$, $x_{33} = 40$, $x_{34} = 50$.

  1. Задаём $u_1 = 0$.
  2. Из клетки С1–П1 ($x_{11} = 40$): $v_1 = c_{11} - u_1 = 2 - 0 = 2$.
  3. Из клетки С1–П3 ($x_{13} = 10$): $v_3 = c_{13} - u_1 = 8 - 0 = 8$.
  4. Из клетки С2–П2 ($x_{22} = 50$): нужно $u_2$ — получим из С2–П3.
  5. Из клетки С2–П3 ($x_{23} = 10$): $u_2 = c_{23} - v_3 = 6 - 8 = -2$; тогда $v_2 = c_{22} - u_2 = 3 - (-2) = 5$.
  6. Из клетки С3–П3 ($x_{33} = 40$): $u_3 = c_{33} - v_3 = 4 - 8 = -4$.
  7. Из клетки С3–П4 ($x_{34} = 50$): $v_4 = c_{34} - u_3 = 2 - (-4) = 6$.

Таблица потенциалов (в клетках — тариф, под ним в скобках — объём; «Δ» — оценки свободных):

С \ П П1 ($v_1 = 2$) П2 ($v_2 = 5$) П3 ($v_3 = 8$) П4 ($v_4 = 6$) $u_i$
С1 2 (40) 4 Δ=−1 8 (10) 7 Δ=+1 0
С2 5 Δ=+5 3 (50) 6 (10) 9 Δ=+5 −2
С3 8 Δ=+10 7 Δ=+6 4 (40) 2 (50) −4

Расчёт оценок свободных клеток:

Улучшающая клетка — С1–П2 ($\Delta_{12} = -1$).

Перераспределение по циклу

Строим цикл через вводимую клетку С1П2 и базисные клетки:

\[С1П2\ (+) \to С1П3\ (-) \to С2П3\ (+) \to С2П2\ (-) \to С1П2\]

(движение: по строке С1 до базисной С1П3, по столбцу П3 до базисной С2П3, по строке С2 до базисной С2П2, по столбцу П2 обратно в С1П2).

Шаг 1. Определяем θ по минусовым клеткам: $\theta = \min(x_{13}, x_{22}) = \min(10, 50) = 10$.

Шаг 2. Пересчитываем план:

Клетка Знак Было Стало
С1П2 + — 10
С1П3 − 10 0 (освобождается)
С2П3 + 10 20
С2П2 − 50 40

Новый план: $x_{11} = 40$, $x_{12} = 10$, $x_{22} = 40$, $x_{23} = 20$, $x_{33} = 40$, $x_{34} = 50$ (базисных клеток снова 6).

Новые затраты:

\[F_1 = 40 \cdot 2 + 10 \cdot 4 + 40 \cdot 3 + 20 \cdot 6 + 40 \cdot 4 + 50 \cdot 2 = 80 + 40 + 120 + 120 + 160 + 100 = 620\ \text{руб.}\]
Улучшение: $630 - 620 = 10$ руб. — ровно $\theta \cdot \Delta_{12} = 10 \cdot 1$, что подтверждает смысл оценки $\Delta_{ij}$: она показывает, на сколько рублей изменятся затраты при перевозке одной единицы по этой клетке.

Итерация 2: проверка улучшенного плана

Расставляем потенциалы заново по новому базису. Пусть $u_1 = 0$:

  1. С1П1: $v_1 = 2 - 0 = 2$.
  2. С1П2: $v_2 = 4 - 0 = 4$.
  3. С2П2: $u_2 = 3 - 4 = -1$.
  4. С2П3: $v_3 = 6 - (-1) = 7$.
  5. С3П3: $u_3 = 4 - 7 = -3$.
  6. С3П4: $v_4 = 2 - (-3) = 5$.
С \ П П1 ($v_1 = 2$) П2 ($v_2 = 4$) П3 ($v_3 = 7$) П4 ($v_4 = 5$) $u_i$
С1 2 (40) 4 (10) 8 Δ=+1 7 Δ=+2 0
С2 5 Δ=+4 3 (40) 6 (20) 9 Δ=+5 −1
С3 8 Δ=+9 7 Δ=+6 4 (40) 2 (50) −3

Оценки свободных клеток: $\Delta_{13} = +1$, $\Delta_{14} = +2$, $\Delta_{21} = +4$, $\Delta_{24} = +5$, $\Delta_{31} = +9$, $\Delta_{32} = +6$ — все Δ ≥ 0, план оптимален.

Оптимальный план и затраты:

\[F^* = 620\ \text{руб.}, \quad x^* = \begin{pmatrix} 40 & 10 & 0 & 0 \\ 0 & 40 & 20 & 0 \\ 0 & 0 & 40 & 50 \end{pmatrix}\]

Сводка итераций:

Итерация План (базисные клетки) Затраты, руб. Минимальная Δ Статус
0 (ММЕ) 40/10/50/10/40/50 630 −1 (С1П2) Не оптимален
1 40/10/40/20/40/50 620 +1 Оптимален

Экономическая интерпретация потенциалов

Потенциалы имеют содержательный смысл условных (теневых) цен:

---
config:
  look: handDrawn
  theme: neutral
---
flowchart TD
    A[Проверка баланса<br/>ΣA = ΣB?] -->|нет| B[Ввести фиктивного<br/>поставщика / потребителя]
    A -->|да| C[Построить опорный план<br/>метод минимального элемента]
    B --> C
    C --> D[Проверить вырожденность:<br/>занятых клеток = m+n−1?]
    D -->|меньше| E[Добавить нулевую<br/>базисную клетку]
    D -->|да| F[Расставить потенциалы<br/>u₁ = 0, uᵢ+vⱼ=cᵢⱼ]
    E --> F
    F --> G[Вычислить Δᵢⱼ свободных клеток]
    G --> H{Все Δᵢⱼ ≥ 0?}
    H -->|да| I[План оптимален<br/>F* — минимальные затраты]
    H -->|нет| J[Выбрать клетку<br/>с min Δᵢⱼ < 0]
    J --> K[Построить цикл,<br/>найти θ, пересчитать план]
    K --> F
    style H fill:#fff9c4,stroke:#333,stroke-width:3px
    style I fill:#c8e6c9,stroke:#333,stroke-width:2px

Инструменты решения

Excel («Поиск решения»)

Настройка (по методике Шадриной Н. И.):

  1. Создать таблицу перевозок: блок ячеек $x_{ij}$ (искомые), рядом — матрица $C_{ij}$, по строкам и столбцам — суммы.
  2. Формула целевой функции: =СУММПРОИЗВ(матрица_перевозок; матрица_стоимостей).
  3. Ограничения:
    • Сумма по строкам ≤ запасы (в закрытой модели — = запасы);
    • Сумма по столбцам ≥ спрос (= спрос);
    • $x_{ij} \geq 0$.
  4. Запустить «Поиск решения»: метод Симплекс ЛП (Simplex LP), целевая ячейка — минимум.
  5. В параметрах solver’а убедиться, что переменные не ограничены целочисленностью (транспортная задача сама даёт целочисленный ответ при целых данных).

Типовая ошибка: выбор метода ОПГ (GRG Nonlinear) вместо «Симплекс ЛП» — задача линейная, нелинейный решатель может остановиться в локальной точке или выдать предупреждение о нелинейности.

Python (Google OR-Tools)

from ortools.linear_solver import pywraplp

# Создание решателя
solver = pywraplp.Solver('Transport', pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)

# Данные задачи 3x4 из примера лекции
costs = [[2, 4, 8, 7],
         [5, 3, 6, 9],
         [8, 7, 4, 2]]
supply = [50, 60, 90]
demand = [40, 50, 60, 50]
m, n = len(supply), len(demand)

# Переменные решения
x = {}
for i in range(m):
    for j in range(n):
        x[i, j] = solver.NumVar(0, solver.infinity(), f'x[{i},{j}]')

# Целевая функция: min sum C_ij * x_ij
solver.Minimize(solver.Sum(
    costs[i][j] * x[i, j] for i in range(m) for j in range(n)))

# Ограничения по запасам: sum_j x_ij = A_i
for i in range(m):
    solver.Add(solver.Sum(x[i, j] for j in range(n)) == supply[i])

# Ограничения по спросу: sum_i x_ij = B_j
for j in range(n):
    solver.Add(solver.Sum(x[i, j] for i in range(m)) == demand[j])

# Решение
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
    print(f'Минимальные затраты: {solver.Objective().Value():.0f} руб.')
    for i in range(m):
        for j in range(n):
            if x[i, j].solution_value() > 0:
                print(f'  С{i+1} -> П{j+1}: {x[i, j].solution_value():.0f} ед.')
# Вывод: затраты 620 руб.; план совпадает с ручным решением

Для больших задач предпочтительна специализированная постановка min-cost flow (ortools.graph.python.min_cost_flow) — она решает транспортную задачу на порядки быстрее общего ЛП-решателя.

Python (PuLP)

from pulp import (LpProblem, LpMinimize, LpVariable, LpStatus,
                  lpSum, value)

costs = [[2, 4, 8, 7], [5, 3, 6, 9], [8, 7, 4, 2]]
supply = [50, 60, 90]
demand = [40, 50, 60, 50]
m, n = len(supply), len(demand)

# Модель
model = LpProblem('Transport', LpMinimize)

# Переменные
x = {(i, j): LpVariable(f'x_{i}_{j}', lowBound=0)
     for i in range(m) for j in range(n)}

# Целевая функция
model += lpSum(costs[i][j] * x[(i, j)]
               for i in range(m) for j in range(n))

# Ограничения баланса
for i in range(m):
    model += lpSum(x[(i, j)] for j in range(n)) == supply[i]
for j in range(n):
    model += lpSum(x[(i, j)] for i in range(m)) == demand[j]

# Решение (по умолчанию CBC)
model.solve()
print('Статус:', LpStatus[model.status])
print('Затраты:', value(model.objective))

Python (SciPy: linprog)

Для быстрой верификации без установки OR-Tools подойдёт встроенный в SciPy решатель HiGHS:

import numpy as np
from scipy.optimize import linprog

C = np.array([[2, 4, 8, 7], [5, 3, 6, 9], [8, 7, 4, 2]])
a, b = np.array([50, 60, 90]), np.array([40, 50, 60, 50])
m, n = C.shape

# Переменные упорядочены по строкам: x11..x14, x21..x24, x31..x34
res = linprog(
    c=C.flatten(),                       # коэффициенты целевой функции
    A_eq=np.vstack([                     # матрица равенств баланса
        np.kron(np.eye(m), np.ones((1, n))),   # по строкам (запасы)
        np.kron(np.ones((1, m)), np.eye(n)),   # по столбцам (спрос)
    ]),
    b_eq=np.concatenate([a, b])[:-1],    # последнее равенство избыточно
    bounds=(0, None),
)
print('Оптимум:', res.fun)               # 620.0
print('План:\n', res.x.reshape(m, n))

Верификация ручного решения

Три независимых инструмента (ручной метод потенциалов, OR-Tools, SciPy HiGHS) дали одинаковый результат: 620 руб. Совпадение решений — обязательный контроль качества: в ручных расчётах типичны арифметические ошибки при расстановке потенциалов и поиске θ.


Транспортная задача большой размерности

Проблемы большой размерности

При большом количестве поставщиков и потребителей:

Пример масштаба сетевой компании:

Методы решения

1. Декомпозиция

2. Специализированные алгоритмы

3. Приближённые алгоритмы (при усложнении постановки)

4. Специализированные решатели

Размерность Рекомендуемый инструмент Время решения
До 5×5 Ручной расчёт (обучение, проверка логики) Минуты
До 50×50 Excel Solver Секунды
До 1000×1000 OR-Tools / PuLP (LP) Секунды
Свыше 10 000 переменных OR-Tools min-cost flow, Gurobi Секунды–минуты
С нелинейными ограничениями Метаэвристики (генетические алгоритмы) Минуты–часы

Учёт ограничений инфраструктуры

Типы ограничений

Пропускная способность маршрутов:

\[x_{ij} \leq Capacity_{ij}\]

Ограничения по типу транспорта:

Временные окна:

Парк подвижного состава:

\[\sum_{j} x_{ij} \leq Fleet_i \cdot Capacity_{vehicle}\]

Запрещённые маршруты задаются тарифом $C_{ij} = \infty$ (или большим числом M): такие клетки исключаются из базиса автоматически.

Пример с ограничениями

Дополнительные условия к базовой задаче 3×4:

Модификация модели (OR-Tools):

# Пропускная способность: x[0,2] <= 80
solver.Add(x[0, 2] <= 80)
# Договорной минимум: x[1,0] >= 50
solver.Add(x[1, 0] >= 50)
# Запрещённый маршрут: фиксация нулём (или Big-M тариф)
solver.Add(x[2, 1] == 0)

Влияние ограничений на решение: каждое дополнительное ограничение сужает допустимое множество и, как правило, увеличивает минимальные затраты (или делает задачу неразрешимой при противоречивых условиях). Разность $F_{огр} - F^*$ — цена ограничения, полезная величина для переговоров: она показывает, сколько стоит ремонт дороги или договорное обязательство.

Многопродуктовая транспортная задача

Если перевозится несколько видов грузов с общей пропускной способностью маршрутов, модель расширяется индексом продукта $k$: переменные $x_{ij}^k$, отдельные балансы по каждому продукту и общие ограничения пропускной способности:

\[\sum_k x_{ij}^k \leq Capacity_{ij}, \quad \sum_j x_{ij}^k = A_i^k, \quad \sum_i x_{ij}^k = B_j^k\]

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


Сравнение Excel и Python

Критерий Excel Python
Простота использования Высокая (GUI) Средняя (требуется код)
Размерность задачи До 200 переменных До 1 000 000+ переменных
Время решения Секунды–минуты Секунды для больших задач
Ручная верификация Наглядно (таблица видна) Требует вывода результата
Интеграция Ограниченная Полная (API, базы данных)
Стоимость Входит в Office Бесплатно (OR-Tools, PuLP)
Визуализация Встроенная Через matplotlib, seaborn
Воспроизводимость Ручные шаги Скрипт (версионируется в git)

Рекомендации по выбору

Ситуация Инструмент
Малые задачи (до 50 переменных), обучение Excel + ручной расчёт
Средние задачи (50–500 переменных) Excel или Python
Большие задачи (500+ переменных) Python (OR-Tools min-cost flow)
Интеграция с ERP/WMS/TMS Python
Быстрый прототип, презентация руководству Excel
Промышленное решение, регулярный пересчёт Python (автоматизация, CI)

Применение на машиностроительном предприятии

Транспортные задачи АО «Ракета»

На машиностроительном предприятии — кейсе курса (АО «Ракета», см. лекцию 1.1) транспортная задача возникает на нескольких уровнях:

Уровень Поставщики Потребители Периодичность решения
Внутризаводской Склад обеспечения, промежуточные склады цехов Переделы: микросборка, агрегаты, сборка Ежедневно/ежесменно
Закупочный Поставщики материалов и электронных компонентов (несколько по каждой позиции) Склад обеспечения Ежемесячно (план закупок)
Сбытовой Склад готовой продукции Заказчики / головной сборочный комплекс По графику отгрузок государственного контракта
Межзаводской Заводы-смежники по кооперации Сборочные площадки По кооперированным поставкам

Пример внутризаводской постановки. Три склада (обеспечения, цеха микросборки, цеха агрегатов) снабжают четыре участка комплектами электронных компонентов. Тариф — стоимость доставки одной партии электротележкой/автопогрузчиком (включая время в пути и обработку). Решение задачи 3×4 из примера выше показывает: оптимально вывозить с дальнего склада (С3) на дальние участки (П4), а ближайший склад (С1) ориентировать на участок П1 — затраты 620 руб. вместо 630 руб. при «жадном» распределении ММЕ.

Особенности задач промышленного предприятия

Особенность Следствие для модели
Приоритет государственного контракта Спрос подразделений, работающих по государственному контракту, — жёсткое равенство; коммерческие заказы — мягкие ограничения
Ограничения на маршруты перевозок Часть маршрутов закрыта (внутризаводские КПП, сопровождение груза) → клетки с $C_{ij} = M$
Спецтранспорт Ограничения пропускной способности по типам ТС; опасные грузы — только сертифицированные маршруты
Прослеживаемость партий Задача дополняется учётом партий (нельзя смешивать поставки разных поставщиков в одной клетке)
Срыв = санкции Целевая функция может включать не только стоимость, но и штраф за риск срыва (двухкритериальная постановка)

Связь с лабораторной работой

Материал лекции является теоретической основой лабораторной работы «Оптимизация транспортных потоков» (семестр 2, выполняется вручную и в Python: Google OR-Tools; результаты сверяются с решением в Excel).

Этап ЛР Теоретическая база лекции
Формализация задачи как транспортной задачи ЛП Постановка, математическая модель, проверка баланса, открытая/закрытая модель
Решение методом минимального элемента (ручной расчёт) Алгоритм ММЕ, пошаговые таблицы распределения, контроль $m + n - 1$
Проверка оптимальности методом потенциалов Расстановка потенциалов, оценки $\Delta_{ij}$, цикл перераспределения, θ
Реализация в Python (Google OR-Tools) Примеры кода (pywraplp, min-cost flow), PuLP, SciPy
Сравнение результатов с решением в Excel Таблица сравнения инструментов, верификация тремя способами
Анализ устойчивости решения к изменению спроса Открытая модель с фиктивным участником, альтернативный оптимум ($\Delta_{ij} = 0$)

Рекомендации по выполнению:

  1. Начинайте с проверки баланса: $\sum A_i = \sum B_j$; при несовпадении введите фиктивного участника и интерпретируйте его загрузку.
  2. Вручную дойдите до оптимального плана и зафиксируйте таблицы всех итераций (потенциалы, оценки, циклы, θ) — это обязательная часть отчёта.
  3. В OR-Tools используйте равенства баланса для закрытой модели; сверьте затраты с ручным решением — расхождение указывает на арифметическую ошибку.
  4. Для анализа устойчивости уменьшите спрос одного потребителя на 10–20% и пересчитайте: сравните изменение затрат с величиной потенциалов.
  5. Проверяйте вырожденность: если занятых клеток меньше $m + n - 1$, метод потенциалов даст неполную систему — добавьте нулевую клетку.

Типовые ошибки при выполнении ЛР:


Ключевые выводы по лекции

  1. Транспортная задача минимизирует затраты на перевозки при ограничениях по запасам и спросу; это частный случай ЛП со специальной структурой матрицы ограничений.

  2. Математическая модель: целевая функция $min \sum\sum C_{ij} x_{ij}$ + ограничения баланса; закрытая модель требует $\sum A_i = \sum B_j$, открытая балансируется фиктивным участником.

  3. Число базисных клеток равно $m + n - 1$; при целых исходных данных оптимум целочисленный автоматически.

  4. Метод минимального элемента строит хороший начальный план (в примере 3×4: 630 руб.); метод северо-западного угла — простейший, но без учёта тарифов; качество начального плана гарантирует только проверка.

  5. Метод потенциалов проверяет оптимальность: все $\Delta_{ij} \geq 0$; при $\Delta_{ij} < 0$ строится цикл, находится $\theta$, план улучшается (в примере: 630 → 620 руб. за одну итерацию).

  6. Экономический смысл оценок: $\Delta_{ij}$ — удорожание перевозки единицы по свободному маршруту; $\Delta_{ij} = 0$ — признак альтернативного оптимума.

  7. Инструменты: Excel (Solver, Симплекс ЛП), Python (OR-Tools, PuLP, SciPy); верификация тремя способами обязательна.

  8. Большая размерность решается потоковыми алгоритмами (min-cost flow, network simplex) и специализированными решателями (Gurobi, OR-Tools).

  9. Ограничения инфраструктуры (пропускная способность, договорные минимумы, запрещённые маршруты) добавляются в модель; их «цена» — разность $F_{огр} - F^*$.

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


Контрольные вопросы

  1. Дайте определение транспортной задачи.
  2. Запишите математическую модель транспортной задачи.
  3. Опишите алгоритм метода минимального элемента.
  4. Как проверяется оптимальность плана методом потенциалов?
  5. Какие инструменты используются для решения транспортных задач?

Рекомендуемая литература

Основная:

  1. Шадрина Н. И. Решение задач оптимизации в Microsoft Excel 2010: учеб. пособие. — Хабаровск: Изд-во ТОГУ, 2016.
  2. Google OR-Tools: документация. — URL: https://developers.google.com/optimization

Дополнительная:

  1. Рахмангулов А. Н. Методологические основы организации функционирования ж.-д. промышленных транспортно-технологических систем: автореф. дис. — Москва, 2013.

Полный каталог и содержание источников — в обзоре литературы.