Масштабирование потока (capacity scaling) — зачем нужно и как ускоряет Форда-Фалкерсона?
Встретил термин «capacity scaling» (масштабирование по пропускной способности) для max-flow. В чём идея этого приёма, как он улучшает асимптотику по сравнению с наивным Форд-Фалкерсоном, и стоит ли его писать на олимпиаде вместо Диница?
2 ответа
Идея масштабирования. Наивный Форд-Фалкерсон плох, когда пропускные большие: он может пускать поток по «тонким» путям много раз. Scaling заставляет алгоритм сначала работать только с толстыми рёбрами.
Заводим порог , начиная с наибольшей степени двойки . На каждой «фазе масштабирования»:
- ищем увеличивающие пути, используя только рёбра с остаточной пропускной ;
- когда таких путей не осталось — делим пополам и повторяем;
- заканчиваем, когда .
Так мы сначала «грубо» набираем поток крупными порциями, потом уточняем. Это гарантирует, что число увеличивающих путей в каждой фазе ограничено .
Асимптотика: , где . Это убирает зависимость от величины потока (в отличие от наивного ) и заменяет её логарифмом от максимальной пропускной — отлично при больших cap и небольшом числе рёбер.
// внутри Форд-Фалкерсона с DFS:
for(long long D = highestPowerOfTwo(maxCap); D >= 1; D >>= 1){
while(dfs_with_threshold(s, t, D)) // ищет путь с остатками >= D
; // пускаем поток
}
Стоит ли писать на олимпиаде? Обычно нет: Диниц (, а на единичных ещё лучше) на практике быстрее и его реализация привычнее. Scaling полезно знать концептуально и для теоретических оценок, а также для некоторых вариантов min-cost flow (cost scaling). Но как рабочую лошадку для max-flow держите Диница.
Концептуально масштабирование родственно идее «двоичного» приближения: каждая фаза с порогом устраняет старший бит «недобора» потока. После фазы остаточный поток (расстояние до оптимума) ограничен , и при делении пополам он быстро сходится. Этот же приём масштабирования (но по стоимости) даёт улучшенные алгоритмы min-cost flow — там он реально применяется чаще, чем scaling для обычного max-flow.