Принцип Беллмана (принцип оптимальности) — это формализация идеи: если некоторая стратегия оптимальна “в целом”, то её “хвост” (оставшаяся часть решений) тоже должен быть оптимален для состояния, в котором мы оказались. Именно поэтому задачи динамического программирования удобно решать “с конца” (backward induction): мы заранее считаем, что в конце периода действуем оптимально, и шаг за шагом “подтягиваем” оптимальность назад.
Ниже — как этим пользоваться на практике, сначала на классике “производство–запасы–поставки”, затем на других типичных задачах.
1) Метод Беллмана “с конца”: общая схема
Любая DP-задача в дискретном времени обычно приводится к 4 элементам:
- Этап (t): время/шаг, обычно t=1,…,T.
- Состояние (st): всё, что нужно знать в момент t, чтобы принимать оптимальное решение, не помня прошлое (например, запас на складе).
- Управление (at): решение на этапе t (например, сколько произвести/заказать).
- Переход: как состояние меняется от решения и внешних факторов:
st+1=f(st,at,случайности)
- Стоимость/выгода: текущая цена решения плюс “стоимость будущего”.
Уравнение Беллмана (детерминированный вариант)
Если всё известно заранее (спрос детерминирован), то:
Vt(s)=a∈A(s)min[ct(s,a)+Vt+1(f(s,a))]
где Vt(s) — минимальная суммарная стоимость с этапа t до конца при условии, что в начале этапа состояние равно s.
“С конца”
- Сначала задаём конечное условие VT+1(s) (например, штраф за остатки или за дефицит).
- Потом считаем VT(⋅), затем VT−1(⋅) … до V1(⋅).
- Параллельно запоминаем оптимальное действие at∗(s) для каждого состояния.
2) Производство–запасы–поставки: типовая постановка
Смысловой пример
Есть горизонт T периодов. В каждом периоде:
- известен спрос dt,
- можно произвести/заказать количество qt≥0,
- на складе есть запас It (inventory),
- стоимость производства/закупки, хранения и (возможно) дефицита.
Динамика запасов (детерминированный спрос):
It+1=It+qt−dt
Часто вводят ограничения: 0≤qt≤Qmax, 0≤It≤Imax.
Если дефицит разрешён, то It может быть отрицательным (это backorder) и тогда добавляют штраф.
Стоимость за период
Один из стандартных вариантов:
ct(It,qt)=K⋅1qt>0+c⋅qt+h⋅(It+1)++p⋅(−(It+1))+
- K — фиксированная стоимость запуска заказа/производства (setup cost),
- c — переменная стоимость за единицу,
- h — хранение на конец периода,
- p — штраф за дефицит/задержку поставки,
- (x)+=max(x,0).
Важно: хранение/дефицит часто считают по запасу после удовлетворения спроса, т.е. по It+1. Это удобно для DP.
3) Как решать “с конца” на мини-числовом примере
Сделаем небольшой горизонт T=3, чтобы руками увидеть механику. Пусть:
- спрос: d1=2, d2=1, d3=2
- решение: qt∈{0,1,2,3}
- начальный запас I1=0
- ограничения на запас: допустим −2≤It≤3 (разрешим небольшой backorder)
- стоимость: переменная c=1, хранение h=1, дефицит p=3, без фиксированной K=0.
- терминальная стоимость: V4(I)=0 (нет штрафа за конечный запас — для простоты)
Шаг 1. Пишем Беллмана
Vt(I)=q∈{0,1,2,3}min[c⋅q+h⋅(I′)++p⋅(−I′)++Vt+1(I′)]
где I′=I+q−dt.
Шаг 2. Считаем с конца: период 3
Так как V4(⋅)=0, то для t=3:
V3(I)=qmin[q+(I′)++3(−I′)+]
и I′=I+q−2.
Интуитивно на последнем периоде выгодно “закрыть” дефицит (штраф 3) и избегать лишнего остатка (хранение 1), но производство тоже стоит 1.
То есть на последнем шаге единица производства “заменяет” единицу дефицита с ценой 3 — почти всегда лучше произвести, если иначе уйдём в минус. А вот производить “в запас” смысла мало, потому что хранение тоже стоит.
Вы можете прямо увидеть правило: на t=3 оптимально выбрать q так, чтобы I′ был как можно ближе к 0, но не уходил в большой минус из-за штрафа.
Шаг 3. Период 2 использует уже найденное V3(⋅)
V2(I)=qmin[q+(I+q−1)++3(−(I+q−1))++V3(I+q−1)]
Шаг 4. Период 1 аналогично
V1(I)=qmin[q+(I+q−2)++3(−(I+q−2))++V2(I+q−2)]
И подставляем I=I1=0.
Что здесь важно понять концептуально:
на шаге t вы не “думаете весь план”. Вы делаете так:
- “Если сейчас запас I и я выберу q, то завтра запас станет I′.”
- “За сегодняшнее решение я плачу ct.”
- “А дальше мне уже известна (или вычисляема) оптимальная стоимость Vt+1(I′).”
- Значит выбираю q, минимизирующий сумму “сегодня + оптимальное завтра”.
Это и есть практическое использование принципа Беллмана.
4) Почему “с конца” — ключ к пониманию
Представьте, что вы стоите в периоде t. Если вы пытаетесь сразу оптимизировать весь план qt,qt+1,…,qT, получается громоздко. Беллман предлагает разложение:
- “Хороший выбор сейчас” = “минимизирует текущую цену + стоимость оптимального будущего, зависящего только от нового состояния”.
Это работает только если состояние выбрано правильно (содержит всю релевантную информацию). В запасах состояние почти всегда — текущий запас/бэклог.
5) Типовые нюансы в задачах запасов/поставок
(A) Фиксированная стоимость запуска заказа (setup cost)
Если есть K⋅1q>0, то оптимальная политика часто становится (s, S):
- если запас высок — не заказывай,
- если ниже порога s — закажи до уровня S.
DP “с конца” это естественно выявляет: на каждом t при каждом I вы сравниваете “0” vs “положительный заказ” с добавлением K.
(B) Ограничения мощностей
Если qt≤Qmax, DP просто сужает множество допустимых управлений A(I).
(C) Случайный спрос (стохастика)
Тогда Беллман становится:
Vt(I)=qmin E[ct(I,q,Dt)+Vt+1(I+q−Dt)]
Вы всё равно считаете “с конца”, но внутри стоит математическое ожидание.
(D) Время поставки (lead time)
Если заказ приходит через L периодов, то состояние надо расширить: включить “заказы в пути”.
Например, st=(It,pipelinet). И DP снова работает.
6) Другие примеры, чтобы закрепить принцип
Пример 1: “Рюкзак” (0/1 Knapsack)
Этап t — рассматриваем предмет t.
Состояние w — оставшаяся грузоподъёмность.
Решение a∈{0,1} — брать/не брать.
Беллман:
Vt(w)=max{Vt+1(w), vt+Vt+1(w−wt)}
(если wt≤w).
“С конца”: начинаете с t=n и двигаетесь назад.
Пример 2: Кратчайший путь в DAG
Этап — “позиция в топологическом порядке”.
Состояние — текущая вершина.
Решение — куда пойти по ребру.
Беллман:
V(v)=(v→u)min{c(v,u)+V(u)}
В DAG можно считать с конца по топологическому порядку.
Пример 3: Замена оборудования (replacement)
Этап — год t.
Состояние — возраст оборудования a.
Решение — “оставить” или “заменить”.
Если оставить: платим эксплуатационные издержки, возраст растёт.
Если заменить: платим цену покупки минус ликвидационную стоимость, возраст сбрасывается.
Беллман даёт оптимальные пороги замены, считается с конца.
7) Практический чек-лист: как “правильно применить Беллмана”
- Чётко определить горизонт T и этапы.
- Выбрать состояние так, чтобы выполнялась “марковость”: будущее зависит от прошлого только через состояние.
- Выписать переход состояния.
- Выписать стоимость этапа (и терминальную стоимость).
- Написать уравнение Беллмана.
- Посчитать с конца, запоминая оптимальные действия.
- Восстановить оптимальную стратегию, идя вперёд от начального состояния.
Если вы хотите, я сделаю следующий шаг: полностью прорешаю числовую задачу по запасам “с конца” (таблично: Vt(I) и оптимальные q для каждого I) — это обычно даёт момент “ага”, потому что видно, как будущая стоимость влияет на решение сегодня.