From ac83a2c52bb264270273c148ff7ae667dfd6011d Mon Sep 17 00:00:00 2001 From: abner-vidal3 Date: Tue, 17 Feb 2026 16:08:49 -0300 Subject: [PATCH] Added min-cut.cpp, bugfix hlpp.cpp, update api for dinic, push-relabel and hlpp, to match min-cut template. --- content/graphs/flow-matching/dinic.cpp | 21 ++++----- content/graphs/flow-matching/hlpp.cpp | 44 +++++++++---------- content/graphs/flow-matching/min-cut.cpp | 29 ++++++++++++ content/graphs/flow-matching/push-relabel.cpp | 42 ++++++++---------- tracker.yaml | 1 + 5 files changed, 80 insertions(+), 57 deletions(-) create mode 100644 content/graphs/flow-matching/min-cut.cpp diff --git a/content/graphs/flow-matching/dinic.cpp b/content/graphs/flow-matching/dinic.cpp index d7755e4..16eae5f 100644 --- a/content/graphs/flow-matching/dinic.cpp +++ b/content/graphs/flow-matching/dinic.cpp @@ -1,11 +1,12 @@ /* - *Author:* Pablo Messina - *Source:* https://github.com/PabloMessina/Competitive-Programming-Material - *Description:* Flow algorithm with complexity $O (|E| dot |V|^2)$ - *Status:* Not tested +*Author:* Pablo Messina +*Source:* https://github.com/PabloMessina/Competitive-Programming-Material +*Description:* Flow algorithm with complexity $O (|E| dot |V|^2)$ +*Status:* Not tested */ +template struct Dinic { - struct Edge { ll to, rev; ll f, c; }; + struct Edge { int to, rev; T f, c; bool r; }; ll n, t_; vector> G; vector D, q, W; bool bfs(ll s, ll t) { @@ -14,7 +15,7 @@ struct Dinic { while (f < l) { ll u = q[f++]; for (const Edge &e : G[u]) if (D[e.to] == -1 && e.f < e.c) - D[e.to] = D[u] + 1, q[l++] = e.to; + D[e.to] = D[u] + 1, q[l++] = e.to; } return D[t] != -1; } @@ -29,13 +30,13 @@ struct Dinic { return 0; } Dinic(ll N) : n(N), G(N), D(N), q(N) {} - void add_edge(ll u, ll v, ll cap) { - G[u].push_back({v, (ll)G[v].size(), 0, cap}); - G[v].push_back({u, (ll)G[u].size() - 1, 0, 0}); // Use cap instead of 0 if bidirectional + void add_edge(int u, int v, T cap) { + G[u].push_back({v, (int)G[v].size(), 0, cap,0}); + G[v].push_back({u, (int)G[u].size()-1, 0, 0,1}); // Use cap instead of 0 if bidirectional } ll max_flow(ll s, ll t) { t_ = t; ll ans = 0; - while (bfs(s, t)) while (ll dl = dfs(s, LLONG_MAX)) ans += dl; + while (bfs(s, t)) while (ll dl = dfs(s, numeric_limits::max())) ans += dl; return ans; } }; \ No newline at end of file diff --git a/content/graphs/flow-matching/hlpp.cpp b/content/graphs/flow-matching/hlpp.cpp index b2cf255..f22395c 100644 --- a/content/graphs/flow-matching/hlpp.cpp +++ b/content/graphs/flow-matching/hlpp.cpp @@ -1,27 +1,24 @@ /* - *Author:* Abner Vidal - *Description:* Flow algorithm with complexity $O (|V|^2 dot sqrt(|E|))$ - *Status:* Tested on CSES +*Author:* Abner Vidal +*Description:* Flow algorithm with complexity $O (|V|^2 dot sqrt(|E|))$ +*Status:* Tested on CSES */ template struct hlpp { - struct edge {int to,rev; T f,c;}; - vector g; vector> adj; - vector h,pt,cnt; vector e; + struct Edge {int to,rev; T f,c; bool r; }; + vector> G; vector h,pt,cnt; vector e; vector> q; int mx,n; - hlpp(int _n) : adj(_n), h(_n,_n), pt(_n,0), cnt(2*_n+1,0), e(_n,0), q(2*_n), mx(-1), n(_n) {} + hlpp(int _n) : G(_n),h(_n,_n), pt(_n,0), cnt(2*_n+1,0), e(_n,0), q(2*_n), mx(-1), n(_n) {} void add_edge(int u, int v, T cap){ - int cur = g.size(); - adj[u].push_back(cur); g.push_back({v,cur+1,0,cap}); - adj[v].push_back(cur+1); g.push_back({u,cur,0,0}); // use cap instead of 0, if bidirectional + G[u].push_back({v,(int)G[v].size(),0,cap,0}); + G[v].push_back({u,(int)G[u].size()-1,0,0,1}); // use cap instead of 0, if bidirectional } void bfs(int s, int t){ queue qr; qr.push(t); h[t] = 0; while (!qr.empty()){ int u = qr.front(); qr.pop(); - for (int ev : adj[u]) { - int v = g[ev].to; - if (h[v] == n && g[g[ev].rev].c-g[g[ev].rev].f > 0) { + for (auto [v,rev,fl,cap,r] : G[u]) { + if (h[v] == n && G[v][rev].c-G[v][rev].f > 0) { h[v] = h[u]+1; cnt[h[v]]++; qr.push(v); } @@ -29,9 +26,9 @@ struct hlpp { } } void push(int u, int ev) { - auto [v,rev,fl,cap] = g[ev]; + auto [v,rev,fl,cap,r] = G[u][ev]; T d = min(e[u],cap-fl); - g[ev].f += d; g[rev].f -= d; + G[u][ev].f += d; G[v][rev].f -= d; e[u] -= d; e[v] += d; if (d != 0 && e[v] == d){ q[h[v]].push_back(v); @@ -50,28 +47,27 @@ struct hlpp { } } int d = 2*n; - for (int ev : adj[u]) { - auto& eg = g[ev]; + for (auto &eg : G[u]) { if (eg.c-eg.f > 0) d = min(d, h[eg.to]); } if (d < 2*n) h[u] = d+1, cnt[h[u]]++; } void discharge(int u) { while (e[u] > 0) { - if (pt[u] < (int)adj[u].size()) { - auto [v,rev,fl,cap] = g[adj[u][pt[u]]]; - if (cap-fl > 0 && h[u] > h[v]) push(u,adj[u][pt[u]]); + if (pt[u] < (int)G[u].size()) { + auto [v,rev,fl,cap,r] = G[u][pt[u]]; + if (cap-fl > 0 && h[u] > h[v]) push(u,pt[u]); else pt[u]++; } else { relabel(u); pt[u] = 0; - if (h[u] >= n) break; + if (h[u] >= 2*n) break; } } } T max_flow(int s, int t){ - bfs(s,t); cnt[0] = n; + bfs(s,t); cnt[0] = 1; h[s] = n; e[s] = numeric_limits::max(); - for (int to : adj[s]) push(s,to); + for (int i = 0; i < (int)G[s].size(); i++) push(s,i); while (mx != -1) { while (mx != -1 && q[mx].empty()) mx--; if (mx == -1) break; @@ -79,7 +75,7 @@ struct hlpp { if (u != s && u != t) discharge(u); } T ans = 0; - for (int to : adj[t]) ans += g[g[to].rev].f; + for (auto &eg : G[t]) ans += G[eg.to][eg.rev].f; return ans; } }; \ No newline at end of file diff --git a/content/graphs/flow-matching/min-cut.cpp b/content/graphs/flow-matching/min-cut.cpp new file mode 100644 index 0000000..6a93736 --- /dev/null +++ b/content/graphs/flow-matching/min-cut.cpp @@ -0,0 +1,29 @@ +/* +*Author:* Abner Vidal +*Description:* Recovers the min-cut after running a max flow algorithm. +*Status:* Tested on codeforces +*/ +template +vector> min_cut(int s, vector> &G){ + int n = G.size(); queue q; + vector vis(n,0); + q.push(s); vis[s] = 1; + while (!q.empty()){ + int p = q.front(); q.pop(); + for (auto & eg : G[p]){ + if (!vis[eg.to] && eg.c-eg.f > 0){ + q.push(eg.to); + vis[eg.to] = 1; + } + } + } + vector> res; + for (int i = 0; i < n; i++){ + if (!vis[i]) continue; + for (auto & eg : G[i]){ + if (vis[eg.to] || eg.r) continue; + res.push_back({i,eg.to}); + } + } + return res; +} \ No newline at end of file diff --git a/content/graphs/flow-matching/push-relabel.cpp b/content/graphs/flow-matching/push-relabel.cpp index f2f548d..db23da1 100644 --- a/content/graphs/flow-matching/push-relabel.cpp +++ b/content/graphs/flow-matching/push-relabel.cpp @@ -1,39 +1,36 @@ /* - *Author:* Abner Vidal - *Description:* Flow algorithm with complexity $O (|E| dot |V|^2)$ - *Status:* Tested on CSES +*Author:* Abner Vidal +*Description:* Flow algorithm with complexity $O (|E| dot |V|^2)$ +*Status:* Tested on CSES */ template struct push_relabel { - struct edge {int to,rev; T f,c;}; - vector g; vector> adj; + struct Edge {int to,rev; T f,c; bool r; }; + vector> G; vector h,pt; vector e; queue q; - push_relabel(int n) : adj(n), h(n,0), e(n,0), pt(n,0) {} + push_relabel(int n) : G(n), h(n,0), e(n,0), pt(n,0) {} void add_edge(int u, int v, T cap){ - int cur = g.size(); - adj[u].push_back(cur); g.push_back({v,cur+1,0,cap}); - adj[v].push_back(cur+1); g.push_back({u,cur,0,0}); + G[u].push_back({v,(int)G[v].size(),0,cap,0}); + G[v].push_back({u,(int)G[u].size()-1,0,0,1}); } void push(int u, int ev) { - auto [v,rev,fl,cap] = g[ev]; + auto [v,rev,fl,cap,r] = G[u][ev]; T d = min(e[u],cap-fl); - g[ev].f += d; g[rev].f -= d; + G[u][ev].f += d; G[v][rev].f -= d; e[u] -= d; e[v] += d; if (d != 0 && e[v] == d) q.push(v); } void relabel(int u) { int d = INT_MAX; - for (int to : adj[u]) { - int v = g[to].to; T cap = g[to].c, fl = g[to].f; - if (cap-fl > 0) d = min(d,h[v]); - } + for (auto &eg : G[u]) + if (eg.c-eg.f > 0) d = min(d,h[eg.to]); if (d < INT_MAX) h[u] = d+1; } void discharge(int u) { while (e[u] > 0) { - if (pt[u] < (int)adj[u].size()) { - auto [v,rev,fl,cap] = g[adj[u][pt[u]]]; - if (cap-fl > 0 && h[u] > h[v]) push(u,adj[u][pt[u]]); + if (pt[u] < (int)G[u].size()) { + auto [v,rev,fl,cap,r] = G[u][pt[u]]; + if (cap-fl > 0 && h[u] > h[v]) push(u,pt[u]); else pt[u]++; } else { relabel(u); pt[u] = 0; @@ -41,15 +38,14 @@ struct push_relabel { } } T max_flow(int s, int t){ - h[s] = (int)adj.size(); e[s] = numeric_limits::max(); - for (int to : adj[s]) push(s,to); + h[s] = (int)G.size(); e[s] = numeric_limits::max(); + for (int i = 0; i < G[s].size(); i++) push(s,i); while (!q.empty()) { int u = q.front(); q.pop(); - if (u != s && u != t) - discharge(u); + if (u != s && u != t) discharge(u); } T ans = 0; - for (int to : adj[t]) ans += g[g[to].rev].f; + for (auto & eg : G[t]) ans += G[eg.to][eg.rev].f; return ans; } }; \ No newline at end of file diff --git a/tracker.yaml b/tracker.yaml index f76244c..ed01984 100644 --- a/tracker.yaml +++ b/tracker.yaml @@ -128,6 +128,7 @@ content: - gomory-hu.cpp - push-relabel.cpp - hlpp.cpp + - min-cut.cpp - trees: - lca.cpp - lca-rmq.cpp