From 417bedf03d62c8fb40d8a56dcdc4c404fdd5a381 Mon Sep 17 00:00:00 2001 From: Horace He Date: Fri, 26 Apr 2019 15:16:40 -0400 Subject: [PATCH 1/6] Added implementation of Dinic's --- content/graph/Dinic.h | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 content/graph/Dinic.h diff --git a/content/graph/Dinic.h b/content/graph/Dinic.h new file mode 100644 index 000000000..6e120a63e --- /dev/null +++ b/content/graph/Dinic.h @@ -0,0 +1,51 @@ +/** + * Author: chilli + * Date: 2019-04-26 + * License: CC0 + * Source: https://cp-algorithms.com/graph/dinic.html + * Description: Flow algorithm with guaranteed complexity $O(V^2E)$. + * On bipartite graphs the complexity is $O(\sqrt{V}E)$, and on unit graphs $O(\min(V^{1/2}, E^{2/3})E)). + * Status: Tested on SPOJ FASTFLOW and SPOJ MATCHING + */ +template struct Dinic { + const T INF = numeric_limits::max(); + struct edge { + int to, rev; + T c, f; + }; + vi lvl, ptr; + vector> adj; + Dinic(int n) : lvl(n), ptr(n), adj(n) {} + void addEdge(int a, int b, T c, int rcap = 0) { + adj[a].push_back({b, sz(adj[b]), c, 0}); + adj[b].push_back({a, sz(adj[a]) - 1, rcap, 0}); + } + T dfs(int v, T f, int t) { + if (v == t || !f) return f; + for (; ptr[v] < sz(adj[v]); ptr[v]++) { + edge &e = adj[v][ptr[v]]; + if (lvl[e.to] != lvl[v] + 1) continue; + if (T p = dfs(e.to, min(f, e.c - e.f), t)) { + e.f += p, adj[e.to][e.rev].f -= p; + return p; + } + } + return 0; + } + ll calc(int s, int t) { + ll flow = 0; + while(true) { + fill(all(ptr), 0), fill(all(lvl), -1), lvl[s] = 0; + queue q({s}); + while (!q.empty() && lvl[t] == -1) { + int v = q.front(); + q.pop(); + trav(e, adj[v]) + if (lvl[e.to] == -1 && e.f < e.c) + q.push(e.to), lvl[e.to] = lvl[v] + 1; + } + if(lvl[t] == -1) return flow; + while (T p = dfs(s, INF, t)) flow += p; + } + } +}; \ No newline at end of file From 8f58fbfea4743112e13e64fed73c9ecda499f982 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Sat, 27 Apr 2019 12:30:42 +0200 Subject: [PATCH 2/6] Codegolf --- content/graph/Dinic.h | 56 +++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/content/graph/Dinic.h b/content/graph/Dinic.h index 6e120a63e..b755b5267 100644 --- a/content/graph/Dinic.h +++ b/content/graph/Dinic.h @@ -7,45 +7,43 @@ * On bipartite graphs the complexity is $O(\sqrt{V}E)$, and on unit graphs $O(\min(V^{1/2}, E^{2/3})E)). * Status: Tested on SPOJ FASTFLOW and SPOJ MATCHING */ -template struct Dinic { - const T INF = numeric_limits::max(); - struct edge { +struct Dinic { + struct Edge { int to, rev; - T c, f; + ll c, f; }; - vi lvl, ptr; - vector> adj; - Dinic(int n) : lvl(n), ptr(n), adj(n) {} - void addEdge(int a, int b, T c, int rcap = 0) { + vi lvl, ptr, q; + vector> adj; + Dinic(int n) : lvl(n), ptr(n), q(n), adj(n) {} + void addEdge(int a, int b, ll c, int rcap = 0) { adj[a].push_back({b, sz(adj[b]), c, 0}); adj[b].push_back({a, sz(adj[a]) - 1, rcap, 0}); } - T dfs(int v, T f, int t) { + ll dfs(int v, int t, ll f) { if (v == t || !f) return f; - for (; ptr[v] < sz(adj[v]); ptr[v]++) { - edge &e = adj[v][ptr[v]]; - if (lvl[e.to] != lvl[v] + 1) continue; - if (T p = dfs(e.to, min(f, e.c - e.f), t)) { - e.f += p, adj[e.to][e.rev].f -= p; - return p; - } + for (int& i = ptr[v]; i < sz(adj[v]); i++) { + Edge& e = adj[v][i]; + if (lvl[e.to] == lvl[v] + 1) + if (ll p = dfs(e.to, t, min(f, e.c - e.f))) { + e.f += p, adj[e.to][e.rev].f -= p; + return p; + } } return 0; } ll calc(int s, int t) { - ll flow = 0; - while(true) { - fill(all(ptr), 0), fill(all(lvl), -1), lvl[s] = 0; - queue q({s}); - while (!q.empty() && lvl[t] == -1) { - int v = q.front(); - q.pop(); + ll flow = 0; q[0] = s; + do { + lvl = ptr = vi(sz(q)); + int qi = 0, qe = lvl[s] = 1; + while (qi < qe && !lvl[t]) { + int v = q[qi++]; trav(e, adj[v]) - if (lvl[e.to] == -1 && e.f < e.c) - q.push(e.to), lvl[e.to] = lvl[v] + 1; + if (!lvl[e.to] && e.f < e.c) + q[qe++] = e.to, lvl[e.to] = lvl[v] + 1; } - if(lvl[t] == -1) return flow; - while (T p = dfs(s, INF, t)) flow += p; - } + while (ll p = dfs(s, t, LLONG_MAX)) flow += p; + } while (lvl[t]); + return flow; } -}; \ No newline at end of file +}; From a41cde95c9f361922485a943dbe07eee0fbcbea8 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Sat, 27 Apr 2019 13:34:45 +0200 Subject: [PATCH 3/6] Update description --- content/graph/Dinic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/graph/Dinic.h b/content/graph/Dinic.h index b755b5267..1693c118d 100644 --- a/content/graph/Dinic.h +++ b/content/graph/Dinic.h @@ -4,7 +4,8 @@ * License: CC0 * Source: https://cp-algorithms.com/graph/dinic.html * Description: Flow algorithm with guaranteed complexity $O(V^2E)$. - * On bipartite graphs the complexity is $O(\sqrt{V}E)$, and on unit graphs $O(\min(V^{1/2}, E^{2/3})E)). + * $O(\sqrt{V}E)$ for bipartite graphs, $O(\min(V^{1/2}, E^{2/3})E))$ for unit graphs. + * To obtain the actual flow, look at positive values only. * Status: Tested on SPOJ FASTFLOW and SPOJ MATCHING */ struct Dinic { From 50ce9539ed8a7971ae443505c484801c468c99cd Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Sat, 27 Apr 2019 13:34:58 +0200 Subject: [PATCH 4/6] Do a full blocking flow --- content/graph/Dinic.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/content/graph/Dinic.h b/content/graph/Dinic.h index 1693c118d..ee2b5cec2 100644 --- a/content/graph/Dinic.h +++ b/content/graph/Dinic.h @@ -22,15 +22,17 @@ struct Dinic { } ll dfs(int v, int t, ll f) { if (v == t || !f) return f; + ll res = 0; for (int& i = ptr[v]; i < sz(adj[v]); i++) { Edge& e = adj[v][i]; if (lvl[e.to] == lvl[v] + 1) if (ll p = dfs(e.to, t, min(f, e.c - e.f))) { e.f += p, adj[e.to][e.rev].f -= p; - return p; + res += p, f -= p; + if (!f) break; } } - return 0; + return res; } ll calc(int s, int t) { ll flow = 0; q[0] = s; From 0fcbfa14aaa5d6ebf4b1a6ec69654cee2031caf6 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Sat, 27 Apr 2019 13:35:26 +0200 Subject: [PATCH 5/6] Add it commented-out to chapter.tex --- content/graph/chapter.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/content/graph/chapter.tex b/content/graph/chapter.tex index a9f9b1790..197db9e9e 100644 --- a/content/graph/chapter.tex +++ b/content/graph/chapter.tex @@ -12,6 +12,7 @@ \section{Network flow} \kactlimport{PushRelabel.h} \kactlimport{MinCostMaxFlow.h} \kactlimport{EdmondsKarp.h} + % \kactlimport{Dinic.h} \kactlimport{MinCut.h} \kactlimport{GlobalMinCut.h} From 3e06b68ad8ed41b56ed163d7d982a428e4b2a4c5 Mon Sep 17 00:00:00 2001 From: Horace He Date: Sat, 27 Apr 2019 15:45:32 -0400 Subject: [PATCH 6/6] Revert "Do a full blocking flow" This reverts commit 50ce9539ed8a7971ae443505c484801c468c99cd. --- content/graph/Dinic.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/content/graph/Dinic.h b/content/graph/Dinic.h index ee2b5cec2..1693c118d 100644 --- a/content/graph/Dinic.h +++ b/content/graph/Dinic.h @@ -22,17 +22,15 @@ struct Dinic { } ll dfs(int v, int t, ll f) { if (v == t || !f) return f; - ll res = 0; for (int& i = ptr[v]; i < sz(adj[v]); i++) { Edge& e = adj[v][i]; if (lvl[e.to] == lvl[v] + 1) if (ll p = dfs(e.to, t, min(f, e.c - e.f))) { e.f += p, adj[e.to][e.rev].f -= p; - res += p, f -= p; - if (!f) break; + return p; } } - return res; + return 0; } ll calc(int s, int t) { ll flow = 0; q[0] = s;