Prerekvizity: [L1.2] Přiřazovací struktura, [L1.4] big-M, [L1.8] Omezení rozptylu (max/min jedné množiny). Nosná úloha je zápočtová School lunch menu design (test 2021): sestavuješ týdenní jídelníček školní jídelny. Tři ze čtyř podmínek zadání jsou techniky, které už máš — čtvrtá („any student orders arbitrary combination of meals“) je dnešní nová věc.
Data: $M = \{1,\dots,100\}$ typů jídel, $D = \{1,\dots,5\}$ dnů; jídlo $m$ má proteiny $p_m$, cenu porce $c_m$ a příznak vegetariánství $v_m \in \{0,1\}$ — vše konstanty (vzpomeň na [L1.12]: příslušnost do skupiny jsou data, součin konstanta × binárka je lineární). Elementární rozhodnutí: je jídlo $m$ v den $d$ na menu?
$$x_{m,d} \in \{0,1\}, \qquad m \in M,\; d \in D, \qquad x_{m,d} = 1 \iff \text{jídlo } m \text{ je v den } d \text{ na menu.}$$Počty na menu jsou součtové podmínky jako v [L1.2]:
$$\sum_{m \in M} x_{m,d} = 4 \quad \forall d \in D, \qquad\qquad \sum_{m \in M} v_m\, x_{m,d} \ge 1 \quad \forall d \in D,$$(„čtyři různá jídla“ je zadarmo — $x_{m,d}$ je jedna binárka na typ jídla, takže 4 jedničky = 4 různé typy; vegetariánský filtr je součin konstanty $v_m$ s binárkou). „Nejvýš jednou za týden“ je součet přes dny:
$$\sum_{d \in D} x_{m,d} \le 1 \quad \forall m \in M.$$A kritérium: každý den se každého jídla na menu uvaří přesně 120 porcí, takže cena týdne je
$$\min\; 120 \sum_{d \in D} \sum_{m \in M} c_m\, x_{m,d}.$$Konstanta 120 optimum nemění (jen škáluje hodnotu kritéria), ale patří do modelu — zadání mluví o ceně týdenního menu.
Zbývá nutriční podmínka: „if any student orders arbitrary combination of meals in the week (exactly one meal per day), his/her total intake of protein must be at least $p^{\min}$“. Tedy: ať si student vybere z menu kterékoli jídlo každý den, součet proteinů jeho pěti jídel musí vyjít aspoň $p^{\min}$. Omezení nekvantifikuje přes jednu množinu čísel, ale přes všechny kombinace voleb.
Protože $\sum_m p_m x_{m,d}$ je součet proteinů všech čtyř jídel na menu — ale student sní každý den jen jedno z nich. Tři jídla s obřím proteinem „dotují“ čtvrté nuzné, a student, který si vybere právě to nuzné, limit nesplní. Podmínka se týká každé volby, ne průměru ani součtu nabídky.
Kombinace = 1 jídlo na den z denního menu: $4^5 = 1024$ kombinací — a obecně $4^{|D|}$, exponenciálně v počtu dnů. A je to ještě horší: menu předem neznáš (rozhoduje o něm sám model), takže bys musel vypsat omezení pro každou pětici jídel z $M$ — to je $100^5 = 10^{10}$ podmíněných omezení, každé „aktivní, jen pokud je všech pět jídel na menu“. Slepá ulička; potřebujeme chytřejší myšlenku.
Volby v jednotlivých dnech jsou nezávislé — výběr v pondělí nijak neomezuje výběr v úterý. Nejméně proteinů tedy nasbírá student, který si každý den vybere proteinové minimum denního menu:
$$\min_{\text{kombinace}} \sum_{d \in D} p_{\text{volba}(d)} \;=\; \sum_{d \in D}\; \min_{m \,\in\, \text{menu}_d} p_m.$$A to je celá pointa: když nejhorší kombinace splní $\ge p^{\min}$, splní ho každá — všechny ostatní jsou po dnech aspoň tak dobré. Místo $4^5$ omezení stačí ohlídat jediné číslo: součet denních minim.
Konstrukce z [L1.8] ($h_{min} \le h_j$ pro všechna $j$) počítá min přes jednu pevnou indexovou množinu (např. všechny muže). Tady je to dvakrát jinak: (1) omezení má platit pro každou kombinaci voleb — to se řeší přechodem na nejhorší případ, žádná „jedna množina hodnot“ tu předem není; (2) denní minimum běží jen přes vybraná jídla ($x_{m,d} = 1$) — množina je sama rozhodnutím modelu, takže nerovnosti se musí pro nevybraná jídla vypnout přes big-M [L1.4]. Kdo na lunch menu napíše holé „L1.8 minimum“, model rozbije (hned uvidíš jak).
Chceme pomocnou proměnnou $z_d$ = „kolik proteinů nejmíň dostane student v den $d$“. Plán podle [L1.8]: svázat $z_d$ shora s hodnotami a součet $\sum_d z_d$ vynutit $\ge p^{\min}$.
Protože by $z_d$ srazilo minimum přes všech 100 jídel v $M$ — i přes ta, která ten den na menu vůbec nejsou! Jediné nízkoproteinové jídlo v katalogu (klidně nikdy nevařené) by stáhlo všechna $z_d$ dolů a podmínka $\sum_d z_d \ge p^{\min}$ by se stala nesplnitelnou, přestože reálné menu je v pořádku — model by se nesmyslně zpřísnil. Nerovnost $z_d \le p_m$ smí „platit“ jen pro jídla s $x_{m,d} = 1$ — a podmíněné omezení = big-M [L1.4]. Pozor na notaci: symbol $M$ je v tomhle zadání obsazený množinou jídel, big-M konstantu proto výjimečně značíme $K$:
$$z_d \;\le\; p_m + K\,(1 - x_{m,d}) \qquad \forall m \in M,\; \forall d \in D.$$Pro $x_{m,d} = 1$ je to ostré $z_d \le p_m$; pro $x_{m,d} = 0$ se pravá strana zvedne o $K$ a omezení nic neřeže.
Vypnutá nerovnost ($x_{m,d}=0$) nesmí řezat žádnou dosažitelnou hodnotu $z_d$. Smysluplné $z_d$ je nejvýš minimum vybraných proteinů, tedy nejvýš $\max_{m} p_m$. Protože proteiny jsou nezáporné ($p_m \ge 0$), je vypnutá pravá strana $p_m + K \ge K$, takže stačí
$$K = \max_{m \in M} p_m$$(těsnější — a platné i bez předpokladu $p_m \ge 0$: $K = \max_m p_m - \min_m p_m$, protože vypnutá pravá strana je pak $p_m + K \ge \min_m p_m + K = \max_m p_m$). Jako vždy u big-M [L1.4]: velikost vždy zdůvodni — dost velké, aby vypnuté omezení neřezalo, ne nesmyslně obří.
Nepotřebuješ — stejná jednostranná logika jako v [L1.8]. Celá konstrukce je:
$$z_d \le p_m + K(1 - x_{m,d}) \;\;\forall m, d, \qquad\qquad \sum_{d \in D} z_d \ge p^{\min}.$$Rozmysli oba směry: (⇒) je-li model přípustný, pak pro každý den $z_d \le \min$ vybraných proteinů, takže nejhorší student dostane $\sum_d \min_{m \in \text{menu}_d} p_m \ge \sum_d z_d \ge p^{\min}$ — podmínka 4 platí. (⇐) splňuje-li menu podmínku 4, polož $z_d := \min_{m \in \text{menu}_d} p_m$ a všechna omezení sedí — žádné dobré menu jsme neuřízli. Solver si $z_d$ „nafoukne“ k dennímu minimu sám, protože potřebuje projít součtovým omezením.
Spočítej si i cenu: $|M| \cdot |D| = 500$ nerovností + 1 součtová — místo $4^5$ kombinací. Polynomiální zápis exponenciálního požadavku.
“Let $M = \{1, \ldots, 100\}$ be a set of different meal types (e.g. schnitzel, lasagne etc.) and let $D = \{1, \ldots, 5\}$ be working days of one specific week. Each portion of meal $m \in M$ provides $p_m$ proteins. For each meal $m \in M$, value $v_m \in \{0, 1\}$ determines whether it is vegetarian or not and value $c_m$ is a cost of cooking one portion of meal $m$.
The goal is to design a school lunch menu for one week such that
1. each day, four different meals from $M$ are on the menu and at least one of them is vegetarian.
2. the cost of the week menu has to be minimized. Every day, exactly 120 portions of each meal on the menu is cooked.
3. each meal $m \in M$ is on the menu at most once per week.
4. to satisfy recommended weekly limits on the nutrition values, it must hold that if any student orders arbitrary combination of meals in the week (exactly one meal per day), his/her total intake of protein must be at least $p^{\min}$.
Formulate this problem as Integer Linear Programming.”
Katalog 100 typů jídel (proteiny $p_m$, cena porce $c_m$, vegetariánský příznak $v_m$ — vše data) a 5 pracovních dnů. Rozhoduješ, co bude který den na menu. Čtyři požadavky: (1) každý den přesně 4 různá jídla, z toho aspoň jedno vegetariánské; (2) minimalizuj cenu — každého jídla na menu se vaří přesně 120 porcí; (3) žádné jídlo se za týden neopakuje; (4) každá studentská kombinace (1 jídlo denně z denního menu) dá za týden aspoň $p^{\min}$ proteinů.
Rozsekej zadání po podmínkách. Elementární rozhodnutí: jídlo × den → binárka (jaké součty přes řádky/sloupce podmínky 1 a 3 chtějí — rovnost, nebo nerovnost?). U kritéria nezapomeň na 120 porcí. Celý vtip je podmínka 4: nejdřív si ujasni, čí proteiny počítáš (jednoho studenta a jeho pět voleb, ne součet menu!), pak najdi nejhorší kombinaci (nezávislost po dnech) a postav denní minima přes $z_d$ — pozor, minimum jen přes vybraná jídla, tedy big-M, ne holé nerovnosti z [L1.8]. Nakonec zkontroluj velikost big-M konstanty (a její značení — $M$ je obsazené).
Proměnné:
$$x_{m,d} \in \{0,1\} \;\; \forall m \in M,\, \forall d \in D \;\;(\text{jídlo } m \text{ na menu dne } d), \qquad z_d \in \mathbb{R} \;\; \forall d \in D.$$(1) Každý den 4 různá jídla, aspoň jedno vegetariánské:
$$\sum_{m \in M} x_{m,d} = 4 \quad \forall d \in D, \qquad\qquad \sum_{m \in M} v_m\, x_{m,d} \ge 1 \quad \forall d \in D.$$(Různost je automatická — jedna binárka na typ jídla; $v_m$ je konstanta, součin je lineární.)
(3) Každé jídlo nejvýš jednou za týden:
$$\sum_{d \in D} x_{m,d} \le 1 \quad \forall m \in M.$$(4) Worst-case proteinová podmínka — denní minimum $z_d$ jen přes vybraná jídla (big-M deaktivace; konstantu značíme $K$, protože $M$ je v zadání obsazené množinou jídel) a součet minim přes týden:
$$z_d \le p_m + K\,(1 - x_{m,d}) \quad \forall m \in M,\, \forall d \in D, \qquad\qquad \sum_{d \in D} z_d \ge p^{\min}, \qquad K = \max_{m \in M} p_m \;(\ge 0).$$Proč to stačí: pro $x_{m,d}=1$ je $z_d \le p_m$, takže $z_d \le \min_{m \in \text{menu}_d} p_m$; součet $\sum_d z_d \ge p^{\min}$ tedy zaručuje, že i student volící každý den nejslabší jídlo nasbírá $\ge p^{\min}$ — a každá jiná kombinace je po dnech aspoň tak dobrá. Obráceně každé vyhovující menu lze doplnit $z_d := \min_{m \in \text{menu}_d} p_m$, takže model žádné dobré menu nezakazuje.
(2) Kritérium — 120 porcí od každého jídla na menu:
$$\min\; 120 \sum_{d \in D} \sum_{m \in M} c_m\, x_{m,d}.$$Celkem $500$ binárek, $5$ spojitých $z_d$ a $O(|M|\cdot|D|)$ lineárních omezení — žádné vypisování kombinací.