← Все вопросы

Что такое максимальный поток в сети и из каких частей он состоит (исток, сток, остаточная сеть)?

Задан 18 месяцев назад203 просмотров2 ответа
9

Готовлюсь к олимпиадам, вижу задачи «найти максимальный поток», но плохо понимаю саму модель. Что такое сеть, исток и сток, пропускные способности? И что за «остаточная сеть», про которую всё время говорят при объяснении Форда-Фалкерсона? Можно строго, но понятно.

2 ответа

16
✓ Принятый ответ — помог автору

Сеть — это ориентированный граф, где у каждого ребра (u,v)(u,v) есть пропускная способность c(u,v)0c(u,v) \ge 0. Выделены две вершины: исток ss (откуда «течёт») и сток tt (куда «втекает»). Поток — это функция f(u,v)f(u,v), удовлетворяющая трём условиям:

  1. Ограничение пропускной способности: 0f(u,v)c(u,v)0 \le f(u,v) \le c(u,v).
  2. Антисимметрия (в одной из формулировок): f(u,v)=f(v,u)f(u,v) = -f(v,u).
  3. Сохранение потока: для любой вершины кроме ss и tt сумма входящего потока равна сумме исходящего.

Величина потока — это суммарный поток, выходящий из истока (он же равен втекающему в сток).

Остаточная сеть — ключевая идея. Для текущего потока ff остаточная пропускная способность ребра — это cf(u,v)=c(u,v)f(u,v)c_f(u,v) = c(u,v) - f(u,v), то есть «сколько ещё можно пустить». Важно: если по ребру (u,v)(u,v) уже течёт ff, то в остаточной сети появляется обратное ребро (v,u)(v,u) с пропускной способностью f(u,v)f(u,v) — оно позволяет «отменить» (откатить) часть ранее пущенного потока. Именно поэтому жадность без обратных рёбер не работает, а с ними — даёт оптимум.

Алгоритмы (Форд-Фалкерсон, Эдмондс-Карп, Диниц) ищут увеличивающий путь sts \to t в остаточной сети и пускают по нему поток, пока такие пути есть. Когда путей нет — поток максимален.

6

Добавлю практическую деталь, на которой все спотыкаются при первой реализации. Обратные рёбра удобно хранить парами в одном массиве рёбер: ребро с индексом ii и его обратное с индексом i1i \oplus 1 (XOR с единицей). Тогда edges[i^1] — это всегда «обратное» к edges[i]. При добавлении ребра сразу кладём два:

struct Edge { int to, cap; };
vector<Edge> e;
vector<vector<int>> g; // g[v] — индексы рёбер из v

void add_edge(int u, int v, int cap) {
    g[u].push_back(e.size()); e.push_back({v, cap});
    g[v].push_back(e.size()); e.push_back({u, 0}); // обратное, cap=0
}

Когда пускаем Δ\Delta по ребру ii: e[i].cap -= d; e[i^1].cap += d;. Это и есть обновление остаточной сети. Обратное ребро стартует с нулевой пропускной — но по мере пуска прямого потока его остаток растёт, и его можно использовать для отката.

Ваш ответ

Войдите, чтобы ответить на вопрос.