网络流-EK求最大流
網(wǎng)絡流-EK求最大流
2021.8.17
網(wǎng)絡流最大流解決什么問題?
網(wǎng)絡流(network-flows)是一種類比水流的解決問題方法(摘自百度百科),最大流是求源點到匯點最大流量的方法。
算法原理
已知起點到終點,很容易想到深搜\廣搜求最大值的方式,但是,在最大流問題中,會出現(xiàn)如下情況:
假設1為源點,4為匯點,若對其進行搜索,路徑可能有1->2->3->4,隨后標記數(shù)組有如下標記:
那么,此時,流經(jīng)1-2線路的水流,匯入了3號節(jié)點最終流向4號節(jié)點,此時3-4路徑已經(jīng)被灌滿,2-4路徑?jīng)]有水流流入,最終匯入?yún)R點的水流量為1。
但是,對于上述情況,最大流應該是如下情形:
此時匯點流入流量為2.
那么,在建圖順序位置時,如何計算出最大的流量?
退回流量,構(gòu)建增廣路徑,當流量匯入其他渠道并且有部分無法匯入?yún)R點,那么就代表其應該回到原渠道,按照原渠道走,但是搜索起來肯定難以實現(xiàn),因此需要建立一條相反的路徑,讓流過去的水流能有機會返回原來的渠道,并且最多返回流過去的水流。(不管水流走在哪里,只要流入?yún)R點即可,不必求出其準確的路徑)如下圖:
如此,在1-3路徑中的水流流入3號節(jié)點時,可以通過2-3路徑流回2號節(jié)點,再從2-4路徑流入4號匯點,此時便可得最大流量為2.(若1-3為2,則也只能退回1).
但是通常情況下,退流一次并不會得到最大流,因此需要多次搜索多次退流。在EK求最大流中,每次選擇在部分流量匯入?yún)R點后,對路徑的可行流進行更改,構(gòu)建增廣路徑。此時圖中每個點的殘留量不影響結(jié)果,因再次搜索時只計算從源點流出的流量。
對其搜索時,正常進行搜索即可:
bool bfs() {queue<int>q;memset(vis, 0, sizeof vis);q.emplace(S); vis[S] = true, d[S] = 0x3f3f3f3f;while (!q.empty()) {int t = q.front(); q.pop();for (int i = head[t]; !i; i = nexte[i]) {int k = to[i];if (!vis[k] && wei[i]) {vis[k] = 1;d[k] = min(d[t], wei[i]);pre[k] = i;if (k == T)return true;q.emplace(k);}}}return false; }其中,d數(shù)組記錄路徑最多流過的流量,pre數(shù)組記錄路徑編號,當成功匯入?yún)R點,則跳出。
每次對路徑進行更新時,則對上一步搜索到的路徑進行退流:
int EK() {int res = 0;while (bfs()) {//搜索直到?jīng)]有可行流res += d[T];for (int i = T; i != S; i = to[pre[i] ^ 1])//建圖時,反向邊編號比正向邊多1wei[pre[i]] -= d[T], wei[pre[i] ^ 1] += d[T];//構(gòu)建增廣路徑}return res; }最終返回的res即為最大流。
注:正向路徑同樣要減去相應的流量大小,因路徑已經(jīng)被部分或全部占用。
模板代碼
代碼
#include<iostream> #include<algorithm> #include<stdio.h> #include<string> #include<string.h> #include<queue>using namespace std;int nexte[20005], wei[20005], to[20005], head[20005]; int n, m, S, T; int idx; int pre[20005], d[20005]; bool vis[20005];void addedge(int u, int v, int c) {to[idx] = v, wei[idx] = c, nexte[idx] = head[u], head[u] = idx++;to[idx] = u, wei[idx] = 0, nexte[idx] = head[v], head[v] = idx++; }bool bfs() {queue<int>q;memset(vis, 0, sizeof vis);q.emplace(S); vis[S] = true, d[S] = 0x3f3f3f3f;while (!q.empty()) {int t = q.front(); q.pop();for (int i = head[t]; !i; i = nexte[i]) {int k = to[i];if (!vis[k] && wei[i]) {d[k] = min(d[t], wei[i]), pre[k] = i;if (k == T)return true;q.emplace(k);vis[k] = 1;}}}return false; }int EK() {int res = 0;while (bfs()) {res += d[T];for (int i = T; i != S; i = to[pre[i] ^ 1])wei[pre[i]] -= d[T], wei[pre[i] ^ 1] += d[T];}return res; }int main() {cin >> n >> m >> S >> T;memset(head, -1, sizeof head);for (int i = 0; i < m; i++){int a, b, c;cin >> a >> b >> c;addedge(a, b, c);}cout << EK() << endl;return 0; }總結(jié)
以上是生活随笔為你收集整理的网络流-EK求最大流的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新一届暑期积分赛题目记录
- 下一篇: 方舟蜘蛛怎么训(洞穴蜘蛛怎么训呢)