Циркуляция потока — различия между версиями
| Lehanyich (обсуждение | вклад) | м (rollbackEdits.php mass rollback) | ||
| (не показано 9 промежуточных версий 8 участников) | |||
| Строка 1: | Строка 1: | ||
| − | |||
| {{Определение | {{Определение | ||
| |definition= | |definition= | ||
| Строка 6: | Строка 5: | ||
| [[Файл:Циркул2.png|frame|справа|Рисунок 1. Пример графа и циркуляции в нем (поток/пропуск.способность)]] | [[Файл:Циркул2.png|frame|справа|Рисунок 1. Пример графа и циркуляции в нем (поток/пропуск.способность)]] | ||
| − | Иначе говоря, [[Определение сети, потока#Определение потока|закон сохранения потока]] <tex>\sum\limits_v f(u,v)=0</tex> должен выполняться для '''всех''' вершин графа, а значит нет нужды в истоке и стоке. Когда все  $l_i$ равны $0$, достаточно пустить поток нулевой величины из каждой вершины, что и будет ответом. Поэтому далее в графе будут существовать  | + | Иначе говоря, [[Определение сети, потока#Определение потока|закон сохранения потока]] <tex>\sum\limits_v f(u,v)=0</tex> должен выполняться для '''всех''' вершин графа, а значит нет нужды в истоке и стоке. Когда все  $l_i$ равны $0$, достаточно пустить поток нулевой величины из каждой вершины, что и будет ответом. Поэтому далее в графе будут существовать рёбра с положительной нижней пропускной способностью. | 
| − | |||
| ==Решение== | ==Решение== | ||
| − | + | Для решения этой задачи заменим исходную сеть $G$ на $G'$ следующим образом. Сначала добавим в граф вершины $s$ {{---}} исток и $t$ {{---}} сток. Для каждого ребра $e_i = v_{from} \xrightarrow{l_i, c_i} v_{to}$ добавим рёбра $s \xrightarrow{0, l_i} v_{to}$ и $u_{from} \xrightarrow{0, l_i} t$, а также сделаем в ребре $e_i$ изменения: $c_i = c_i - l_i, l_i = 0$ (см. рисунок 2). | |
| − | [[Файл:Циркуляция.png|frame|center|Рисунок 2. Слева - изначальный граф. Для каждого ребра заданы его нижняя и верхняя пропускные способности. Справа - граф после преобразований  | + | [[Файл:Циркуляция.png|frame|center|Рисунок 2. Слева - изначальный граф. Для каждого ребра заданы его нижняя и верхняя пропускные способности. Справа - граф после преобразований рёбер.]] | 
| − | Каждое ребро изначального графа заменяется на три новых. Если по ребру $e_i = (v_{from}, v_{to})$ в исходной сети протекает поток $l_i \leqslant f_i \leqslant c_i$, то в новой сети по ребру $(s, v_{to})$ должен течь поток, равный $l_i$, то есть его пропускной способности. Поток, который вытекает из $v_{from}$ по ребру в $G$, заменяется на поток, который протекает по  | + | Каждое ребро изначального графа заменяется на три новых. Если по ребру $e_i = (v_{from}, v_{to})$ в исходной сети протекает поток $l_i \leqslant f_i \leqslant c_i$, то в новой сети по ребру $(s, v_{to})$ должен течь поток, равный $l_i$, то есть его пропускной способности. Поток, который вытекает из $v_{from}$ по ребру в $G$, заменяется на поток, который протекает по рёбрам $(v_{from}, v_{to})$ и $(v_{from}, t)$ (поскольку сумма их пропускных способностей в полученном графе равна $c_i$). Аналогично, для вершины $v_{to}$ суммарный входящий поток не изменился. Таким образом, любой допустимый поток по любому ребру в изначальном графе можно распределить между тремя рёбрами в полученном графе. Заметим, что в сети $G'$ все $l_i = 0$, то есть мы имеем обыкновенную сеть. | 
| − | Требовалось найти циркуляцию в исходной сети, а значит проверить существование потока, для которого выполнено равенство <tex>\sum\limits_v f(u,v) = 0</tex> для всех вершин графа. Это равносильно существованию потока между вершинами $s$ и $t$ в сети $G'$, который полностью насытит  | + | Требовалось найти циркуляцию в исходной сети, а значит проверить существование потока, для которого выполнено равенство <tex>\sum\limits_v f(u,v) = 0</tex> для всех вершин графа. Это равносильно существованию потока между вершинами $s$ и $t$ в сети $G'$, который полностью насытит рёбра, исходящие из истока. Действительно, этот поток в исходном графе насытит $i$-ое ребро как минимум на $l_i$, что и является необходимым требованием. Если этот поток существует, то будет выполнено: | 
| * $\sum\limits_v f(u,v)=0,$ где $u \in V'-\{s,t\}, v \in V'$, то есть для всех исходных вершин; | * $\sum\limits_v f(u,v)=0,$ где $u \in V'-\{s,t\}, v \in V'$, то есть для всех исходных вершин; | ||
| * В $G': f_i \leqslant c_i - l_i \Rightarrow 0 \leqslant f_i \leqslant c_i - l_i \Rightarrow l_i \leqslant f_i + l_i \leqslant c_i$, что удовлетворяет всем ограничениям. | * В $G': f_i \leqslant c_i - l_i \Rightarrow 0 \leqslant f_i \leqslant c_i - l_i \Rightarrow l_i \leqslant f_i + l_i \leqslant c_i$, что удовлетворяет всем ограничениям. | ||
| Значит, этот поток и есть циркуляция.   | Значит, этот поток и есть циркуляция.   | ||
| − | Запустим в новой сети один из алгоритмов поиска максимального потока. Если он не смог полностью насытить все  | + | Запустим в новой сети один из алгоритмов поиска максимального потока. Если он не смог полностью насытить все рёбра из истока, то и никакой другой по величине поток этого сделать не сможет, значит, циркуляции нет. Для получения величин потоков вдоль каждого ребра в изначальной сети достаточно прибавить к потокам вдоль рёбер в сети $G'$ соответствующие значения минимальной пропускной способности. | 
| − | |||
| ==Псевдокод== | ==Псевдокод== | ||
| − |   '''function''' circulation(<tex>V,E</tex>) | + | Конструктор ребра принимает следующие аргументы: | 
| − |       <tex>G=\varnothing</tex>  | + | * <tex>\mathtt{from}</tex> {{---}} вершина начала ребра | 
| − |       '''for''' <tex>e : e\in E</tex | + | * <tex>\mathtt{to}</tex> {{---}} вершина конца ребра | 
| − |           <tex> | + | * <tex>\mathtt{minCap}</tex> {{---}} минимальная пропускная способность ребра | 
| − |           <tex> | + | * <tex>\mathtt{maxCap}</tex> {{---}} максимальная пропускная способность ребра | 
| − |           <tex> | + |   '''function''' circulation(<tex>V,E</tex>): | 
| − |           <tex>G = G \cup  | + |       <tex>G'=</tex> (<tex>V \cup s \cup t</tex>, <tex>\varnothing</tex>)                                 <font color=green>// создаём новый граф с исходными вершинами и добавлением s и t {{---}} исток и сток</font> | 
| − |       maxFlow = getMaxFlow(<tex>G</tex>)                             <font color=green>// наибольший поток в графе G</font> | + |       '''for''' <tex>e : e\in E</tex> | 
| − |       '''for''' <tex>e : e\in E</tex> '''and''' <tex>e</tex>.from <tex>=s</tex> | + |           <tex>g</tex> = Edge(<tex>s</tex>, <tex>e</tex>.to, <tex>0</tex>, <tex>e</tex>.minCap) | 
| − |           '''if''' <tex>f</tex>(<tex>e</tex>)<tex> < e</tex>. | + |           <tex>h</tex> = Edge(<tex>e</tex>.from, <tex>e</tex>.to, <tex>0</tex>, <tex>e</tex>.maxCap - <tex>e</tex>.minCap) | 
| + |           <tex>k</tex> = Edge(<tex>e</tex>.from, <tex>t</tex>, <tex>0</tex>, <tex>e</tex>.minCap) | ||
| + |           <tex>G'=G' \cup </tex>(<tex>\varnothing</tex>, <tex>g \cup h \cup k</tex>) | ||
| + |       maxFlow = getMaxFlow(<tex>G'</tex>)                             <font color=green>// наибольший поток в графе G'</font> | ||
| + |       '''for''' <tex>e : e\in E'</tex> '''and''' <tex>e</tex>.from <tex>=s</tex> | ||
| + |           '''if''' <tex>f</tex>(<tex>e</tex>) <tex> < e</tex>.maxCap                              <font color=green>// если для текущего ребра flow < cap</font> | ||
|               '''return''' false |               '''return''' false | ||
|       '''return''' true |       '''return''' true | ||
Текущая версия на 19:19, 4 сентября 2022
| Определение: | 
| Поток нулевой величины в сети $G(V, E)$ называется циркуляцией (англ. circulation problem). Каждое ребро $e_i$ имеет $l_i$ и $c_i$ — минимальная и максимальная пропускная способности соответственно. Необходимо выяснить, существует ли в этой сети циркуляция, удовлетворяющая пропускным способностям рёбер. | 
Иначе говоря, закон сохранения потока должен выполняться для всех вершин графа, а значит нет нужды в истоке и стоке. Когда все $l_i$ равны $0$, достаточно пустить поток нулевой величины из каждой вершины, что и будет ответом. Поэтому далее в графе будут существовать рёбра с положительной нижней пропускной способностью.
Решение
Для решения этой задачи заменим исходную сеть $G$ на $G'$ следующим образом. Сначала добавим в граф вершины $s$ — исток и $t$ — сток. Для каждого ребра $e_i = v_{from} \xrightarrow{l_i, c_i} v_{to}$ добавим рёбра $s \xrightarrow{0, l_i} v_{to}$ и $u_{from} \xrightarrow{0, l_i} t$, а также сделаем в ребре $e_i$ изменения: $c_i = c_i - l_i, l_i = 0$ (см. рисунок 2).
Каждое ребро изначального графа заменяется на три новых. Если по ребру $e_i = (v_{from}, v_{to})$ в исходной сети протекает поток $l_i \leqslant f_i \leqslant c_i$, то в новой сети по ребру $(s, v_{to})$ должен течь поток, равный $l_i$, то есть его пропускной способности. Поток, который вытекает из $v_{from}$ по ребру в $G$, заменяется на поток, который протекает по рёбрам $(v_{from}, v_{to})$ и $(v_{from}, t)$ (поскольку сумма их пропускных способностей в полученном графе равна $c_i$). Аналогично, для вершины $v_{to}$ суммарный входящий поток не изменился. Таким образом, любой допустимый поток по любому ребру в изначальном графе можно распределить между тремя рёбрами в полученном графе. Заметим, что в сети $G'$ все $l_i = 0$, то есть мы имеем обыкновенную сеть.
Требовалось найти циркуляцию в исходной сети, а значит проверить существование потока, для которого выполнено равенство для всех вершин графа. Это равносильно существованию потока между вершинами $s$ и $t$ в сети $G'$, который полностью насытит рёбра, исходящие из истока. Действительно, этот поток в исходном графе насытит $i$-ое ребро как минимум на $l_i$, что и является необходимым требованием. Если этот поток существует, то будет выполнено:
- $\sum\limits_v f(u,v)=0,$ где $u \in V'-\{s,t\}, v \in V'$, то есть для всех исходных вершин;
- В $G': f_i \leqslant c_i - l_i \Rightarrow 0 \leqslant f_i \leqslant c_i - l_i \Rightarrow l_i \leqslant f_i + l_i \leqslant c_i$, что удовлетворяет всем ограничениям.
Значит, этот поток и есть циркуляция.
Запустим в новой сети один из алгоритмов поиска максимального потока. Если он не смог полностью насытить все рёбра из истока, то и никакой другой по величине поток этого сделать не сможет, значит, циркуляции нет. Для получения величин потоков вдоль каждого ребра в изначальной сети достаточно прибавить к потокам вдоль рёбер в сети $G'$ соответствующие значения минимальной пропускной способности.
Псевдокод
Конструктор ребра принимает следующие аргументы:
- — вершина начала ребра
- — вершина конца ребра
- — минимальная пропускная способность ребра
- — максимальная пропускная способность ребра
function circulation(): (, ) // создаём новый граф с исходными вершинами и добавлением s и t — исток и сток for = Edge(, .to, , .minCap) = Edge(.from, .to, , .maxCap - .minCap) = Edge(.from, , , .minCap) (, ) maxFlow = getMaxFlow() // наибольший поток в графе G' for and .from if () .maxCap // если для текущего ребра flow < cap return false return true


