Как задать пропускную способность на вершине (vertex capacity) в задаче о потоке?
В задаче ограничение не на рёбра, а на вершины: через вершину может пройти не более единиц потока. Классический max-flow умеет только рёберные ограничения. Как свести вершинные пропускные к обычной задаче о потоке?
2 ответа
Приём «расщепление вершины» (vertex splitting). Каждую вершину с пропускной способностью заменяем на две: и , соединённые ребром с пропускной способностью .
Правило перенаправления рёбер:
- все рёбра, входившие в , теперь входят в ;
- все рёбра, выходившие из , теперь выходят из .
Теперь весь поток, проходящий через , обязан пройти по «внутреннему» ребру , и его пропускная способность ограничивает поток через вершину. Дальше — обычный max-flow.
// нумерация: vin(v) = 2*v, vout(v) = 2*v+1
for(int v=0; v<V; v++) add_edge(2*v, 2*v+1, capVertex[v]); // ребро вершины
for(auto&[u,w,c]:origEdges) add_edge(2*u+1, 2*w, c); // u_out -> w_in
int flow = maxflow(2*s+1, 2*t); // источник — это s_out, сток — t_in
Размер сети удваивается по вершинам () и добавляется рёбер — это накладных расходов, асимптотика алгоритма не меняется. Этот приём — основа множества задач: «максимум вершинно-непересекающихся путей» (теорема Менгера), задачи с лимитами на узлы сети и т.п.
Внимание к истоку и стоку при расщеплении: для них тоже создаются /, но запускать поток надо из в (как в коде выше), иначе вы случайно ограничите сам исток/сток. Если у и нет своего лимита, можно либо ставить им на внутреннем ребре, либо вообще не расщеплять их и брать как , как напрямую. Главное — быть последовательным в нумерации, иначе тихо получите неверный ответ.