Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions content/graphs/flow-matching/dinic.cpp
Original file line number Diff line number Diff line change
@@ -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<class T>
struct Dinic {
struct Edge { ll to, rev; ll f, c; };
struct Edge { int to, rev; T f, c; bool r; };
ll n, t_; vector<vector<Edge>> G;
vector<ll> D, q, W;
bool bfs(ll s, ll t) {
Expand All @@ -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;
}
Expand All @@ -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<T>::max())) ans += dl;
return ans;
}
};
44 changes: 20 additions & 24 deletions content/graphs/flow-matching/hlpp.cpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
/*
*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<class T>
struct hlpp {
struct edge {int to,rev; T f,c;};
vector<edge> g; vector<vector<int>> adj;
vector<int> h,pt,cnt; vector<T> e;
struct Edge {int to,rev; T f,c; bool r; };
vector<vector<Edge>> G; vector<int> h,pt,cnt; vector<T> e;
vector<vector<int>> 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<int> 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);
}
}
}
}
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);
Expand All @@ -50,36 +47,35 @@ 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<T>::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;
int u = q[mx].back(); q[mx].pop_back();
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;
}
};
29 changes: 29 additions & 0 deletions content/graphs/flow-matching/min-cut.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
*Author:* Abner Vidal
*Description:* Recovers the min-cut after running a max flow algorithm.
*Status:* Tested on codeforces
*/
template<class Edge>
vector<array<int,2>> min_cut(int s, vector<vector<Edge>> &G){
int n = G.size(); queue<int> q;
vector<bool> 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<array<int,2>> 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;
}
42 changes: 19 additions & 23 deletions content/graphs/flow-matching/push-relabel.cpp
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
/*
*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<class T>
struct push_relabel {
struct edge {int to,rev; T f,c;};
vector<edge> g; vector<vector<int>> adj;
struct Edge {int to,rev; T f,c; bool r; };
vector<vector<Edge>> G;
vector<int> h,pt; vector<T> e; queue<int> 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;
}
}
}
T max_flow(int s, int t){
h[s] = (int)adj.size(); e[s] = numeric_limits<T>::max();
for (int to : adj[s]) push(s,to);
h[s] = (int)G.size(); e[s] = numeric_limits<T>::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;
}
};
1 change: 1 addition & 0 deletions tracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ content:
- gomory-hu.cpp
- push-relabel.cpp
- hlpp.cpp
- min-cut.cpp
- trees:
- lca.cpp
- lca-rmq.cpp
Expand Down
Loading