summaryrefslogtreecommitdiff
path: root/graph
diff options
context:
space:
mode:
authorGloria Mundi <gloria@gloria-mundi.eu>2024-11-16 01:24:14 +0100
committerGloria Mundi <gloria@gloria-mundi.eu>2024-11-16 01:24:14 +0100
commit98567ec798aa8ca2cfbcb85c774dd470f30e30d4 (patch)
tree5113d5cc24d1ad5f93810b6442ce584a36950dc8 /graph
parentad3856a6b766087df0036de0b556f4700a6498c9 (diff)
parent8d11c6c8213f46f0fa19826917c255edd5d43cb1 (diff)
mzuenni tests
Diffstat (limited to 'graph')
-rw-r--r--graph/2sat.cpp31
-rw-r--r--graph/LCA_sparse.cpp32
-rw-r--r--graph/TSP.cpp28
-rw-r--r--graph/articulationPoints.cpp45
-rw-r--r--graph/bellmannFord.cpp17
-rw-r--r--graph/binary_lifting.cpp28
-rw-r--r--graph/bitonicTSP.cpp31
-rw-r--r--graph/bitonicTSPsimple.cpp28
-rw-r--r--graph/blossom.cpp82
-rw-r--r--graph/bronKerbosch.cpp24
-rw-r--r--graph/capacityScaling.cpp44
-rw-r--r--graph/centroid.cpp21
-rw-r--r--graph/connect.cpp31
-rw-r--r--graph/cycleCounting.cpp64
-rw-r--r--graph/dfs.tex16
-rw-r--r--graph/dijkstra.cpp21
-rw-r--r--graph/dinicScaling.cpp51
-rw-r--r--graph/euler.cpp23
-rw-r--r--graph/floydWarshall.cpp26
-rw-r--r--graph/graph.tex285
-rw-r--r--graph/havelHakimi.cpp18
-rw-r--r--graph/hld.cpp44
-rw-r--r--graph/hopcroftKarp.cpp47
-rw-r--r--graph/kruskal.cpp9
-rw-r--r--graph/matching.cpp23
-rw-r--r--graph/maxCarBiMatch.cpp25
-rw-r--r--graph/maxWeightBipartiteMatching.cpp50
-rw-r--r--graph/minCostMaxFlow.cpp66
-rw-r--r--graph/pushRelabel.cpp64
-rw-r--r--graph/reroot.cpp62
-rw-r--r--graph/scc.cpp32
-rw-r--r--graph/stoerWagner.cpp53
-rw-r--r--graph/test/LCA_sparse.cpp63
-rw-r--r--graph/test/binary_lifting.cpp67
-rw-r--r--graph/test/util.cpp60
-rw-r--r--graph/treeIsomorphism.cpp15
-rw-r--r--graph/virtualTree.cpp22
37 files changed, 0 insertions, 1648 deletions
diff --git a/graph/2sat.cpp b/graph/2sat.cpp
deleted file mode 100644
index 75e54e6..0000000
--- a/graph/2sat.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-struct sat2 {
- int n; // + scc variablen
- vector<int> sol;
-
- sat2(int vars) : n(vars*2), adj(n) {}
-
- static int var(int i) {return i << 1;} // use this!
-
- void addImpl(int a, int b) {
- adj[a].push_back(b);
- adj[1^b].push_back(1^a);
- }
- void addEquiv(int a, int b) {addImpl(a, b); addImpl(b, a);}
- void addOr(int a, int b) {addImpl(1^a, b);}
- void addXor(int a, int b) {addOr(a, b); addOr(1^a, 1^b);}
- void addTrue(int a) {addImpl(1^a, a);}
- void addFalse(int a) {addTrue(1^a);}
- void addAnd(int a, int b) {addTrue(a); addTrue(b);}
- void addNand(int a, int b) {addOr(1^a, 1^b);}
-
- bool solve() {
- scc(); //scc code von oben
- sol.assign(n, -1);
- for (int i = 0; i < n; i += 2) {
- if (idx[i] == idx[i + 1]) return false;
- sol[i] = idx[i] < idx[i + 1];
- sol[i + 1] = !sol[i];
- }
- return true;
- }
-};
diff --git a/graph/LCA_sparse.cpp b/graph/LCA_sparse.cpp
deleted file mode 100644
index 3e87cde..0000000
--- a/graph/LCA_sparse.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-struct LCA {
- vector<ll> depth;
- vector<int> visited, first;
- int idx;
- SparseTable st; //sparse table @\sourceref{datastructures/sparseTable.cpp}@
-
- void init(vector<vector<int>>& adj, int root) {
- depth.assign(2 * sz(adj), 0);
- visited.assign(2 * sz(adj), -1);
- first.assign(sz(adj), 2 * sz(adj));
- idx = 0;
- dfs(adj, root);
- st.init(depth);
- }
-
- void dfs(vector<vector<int>>& adj, int v, ll d=0) {
- visited[idx] = v, depth[idx] = d;
- first[v] = min(idx, first[v]), idx++;
-
- for (int u : adj[v]) {
- if (first[u] == 2 * sz(adj)) {
- dfs(adj, u, d + 1);
- visited[idx] = v, depth[idx] = d, idx++;
- }}}
-
- int getLCA(int u, int v) {
- if (first[u] > first[v]) swap(u, v);
- return visited[st.queryIdempotent(first[u], first[v] + 1)];
- }
-
- ll getDepth(int v) {return depth[first[v]];}
-};
diff --git a/graph/TSP.cpp b/graph/TSP.cpp
deleted file mode 100644
index cfb1b4d..0000000
--- a/graph/TSP.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-vector<vector<ll>> dist; // Entfernung zwischen je zwei Punkten.
-
-void TSP() {
- int n = sz(dist), m = 1 << n;
- vector<vector<edge>> dp(n, vector<edge>(m, edge{INF, -1}));
-
- for (int c = 0; c < n; c++)
- dp[c][m-1].dist = dist[c][0], dp[c][m-1].to = 0;
-
- for (int v = m - 2; v >= 0; v--) {
- for (int c = n - 1; c >= 0; c--) {
- for (int g = 0; g < n; g++) {
- if (g != c && !((1 << g) & v)) {
- if ((dp[g][(v | (1 << g))].dist + dist[c][g]) <
- dp[c][v].dist) {
- dp[c][v].dist =
- dp[g][(v | (1 << g))].dist + dist[c][g];
- dp[c][v].to = g;
- }}}}}
- // return dp[0][1]; // Länge der Tour
-
- vector<int> tour; tour.push_back(0); int v = 0;
- while (tour.back() != 0 || sz(tour) == 1)
- tour.push_back(dp[tour.back()]
- [(v |= (1 << tour.back()))].to);
- // Enthält Knoten 0 zweimal. An erster und letzter Position.
- // return tour;
-}
diff --git a/graph/articulationPoints.cpp b/graph/articulationPoints.cpp
deleted file mode 100644
index 6819bf3..0000000
--- a/graph/articulationPoints.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-vector<vector<Edge>> adj;
-vector<int> num;
-int counter, rootCount, root;
-vector<bool> isArt;
-vector<Edge> bridges, st;
-vector<vector<Edge>> bcc;
-
-int dfs(int v, int from = -1) {
- int me = num[v] = ++counter, top = me;
- for (Edge& e : adj[v]) {
- if (e.id == from){}
- else if (num[e.to]) {
- top = min(top, num[e.to]);
- if (num[e.to] < me) st.push_back(e);
- } else {
- if (v == root) rootCount++;
- int si = sz(st);
- int up = dfs(e.to, e.id);
- top = min(top, up);
- if (up >= me) isArt[v] = true;
- if (up > me) bridges.push_back(e);
- if (up <= me) st.push_back(e);
- if (up == me) {
- bcc.emplace_back();
- while (sz(st) > si) {
- bcc.back().push_back(st.back());
- st.pop_back();
- }}}}
- return top;
-}
-
-void find() {
- counter = 0;
- num.assign(sz(adj), 0);
- isArt.assign(sz(adj), false);
- bridges.clear();
- st.clear();
- bcc.clear();
- for (int v = 0; v < sz(adj); v++) {
- if (!num[v]) {
- root = v;
- rootCount = 0;
- dfs(v);
- isArt[v] = rootCount > 1;
-}}}
diff --git a/graph/bellmannFord.cpp b/graph/bellmannFord.cpp
deleted file mode 100644
index 4324886..0000000
--- a/graph/bellmannFord.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-void bellmannFord(int n, vector<edge> edges, int start) {
- vector<ll> dist(n, INF), parent(n, -1);
- dist[start] = 0;
-
- for (int i = 1; i < n; i++) {
- for (edge& e : edges) {
- if (dist[e.from] != INF &&
- dist[e.from] + e.cost < dist[e.to]) {
- dist[e.to] = dist[e.from] + e.cost;
- parent[e.to] = e.from;
- }}}
-
- for (edge& e : edges) {
- if (dist[e.from] != INF &&
- dist[e.from] + e.cost < dist[e.to]) {
- // Negativer Kreis gefunden.
-}}} //return dist, parent?;
diff --git a/graph/binary_lifting.cpp b/graph/binary_lifting.cpp
deleted file mode 100644
index 0b8c218..0000000
--- a/graph/binary_lifting.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-struct Lift {
- vector<int> dep, par, jmp;
-
- Lift(vector<vector<int>> &adj, int root):
- dep(adj.size()), par(adj.size()), jmp(adj.size(), root) {
- function<void(int,int,int)> dfs = [&](int u, int p, int d) {
- dep[u] = d, par[u] = p;
- jmp[u] = dep[p] + dep[jmp[jmp[p]]] == 2*dep[jmp[p]]
- ? jmp[jmp[p]] : p;
- for (int v: adj[u]) if (v != p) dfs(v, u, d+1);
- };
- dfs(root, root, 0);
- }
-
- int depth(int v) { return dep[v]; }
- int lift(int v, int d) {
- while (dep[v] > d) v = dep[jmp[v]] < d ? par[v] : jmp[v];
- return v;
- }
- int lca(int u, int v) {
- v = lift(v, dep[u]), u = lift(u, dep[v]);
- while (u != v) {
- auto &a = jmp[u] == jmp[v] ? par : jmp;
- u = a[u], v = a[v];
- }
- return u;
- }
-};
diff --git a/graph/bitonicTSP.cpp b/graph/bitonicTSP.cpp
deleted file mode 100644
index e8fc2cb..0000000
--- a/graph/bitonicTSP.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-vector<vector<double>> dist; // Initialisiere mit Entfernungen zwischen Punkten.
-
-void bitonicTSP() {
- vector<double> dp(sz(dist), HUGE_VAL);
- vector<int> pre(sz(dist)); // nur für Tour
- dp[0] = 0; dp[1] = 2 * dist[0][1]; pre[1] = 0;
- for (unsigned int i = 2; i < sz(dist); i++) {
- double link = 0;
- for (int j = i - 2; j >= 0; j--) {
- link += dist[j + 1][j + 2];
- double opt = link + dist[j][i] + dp[j + 1] - dist[j][j + 1];
- if (opt < dp[i]) {
- dp[i] = opt;
- pre[i] = j;
- }}}
- // return dp.back(); // Länger der Tour
-
- int j, n = sz(dist) - 1;
- vector<int> ut, lt = {n, n - 1};
- do {
- j = pre[n];
- (lt.back() == n ? lt : ut).push_back(j);
- for (int i = n - 1; i > j + 1; i--) {
- (lt.back() == i ? lt : ut).push_back(i - 1);
- }
- } while(n = j + 1, j > 0);
- (lt.back() == 1 ? lt : ut).push_back(0);
- reverse(all(lt));
- lt.insert(lt.end(), all(ut));
- //return lt;// Enthält Knoten 0 zweimal. An erster und letzter Position.
-}
diff --git a/graph/bitonicTSPsimple.cpp b/graph/bitonicTSPsimple.cpp
deleted file mode 100644
index 96ae5bd..0000000
--- a/graph/bitonicTSPsimple.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-vector<vector<double>> dist; // Entfernungen zwischen Punkten.
-vector<vector<double>> dp;
-
-double get(int p1, int p2) {
- int v = max(p1, p2) + 1;
- if (v == sz(dist)) return dist[p1][v - 1] + dist[p2][v - 1];
- if (dp[p1][p2] >= 0.0) return dp[p1][p2];
- double tryLR = dist[p1][v] + get(v, p2);
- double tryRL = dist[p2][v] + get(p1, v);
- return dp[p1][p2] = min(tryLR, tryRL);
-}
-
-void bitonicTour() {
- dp = vector<vector<double>>(sz(dist),
- vector<double>(sz(dist), -1));
- get(0, 0);
- // return dp[0][0]; // Länger der Tour
- vector<int> lr = {0}, rl = {0};
- for (int p1 = 0, p2 = 0, v; (v = max(p1, p2)+1) < sz(dist);) {
- if (dp[p1][p2] == dist[p1][v] + dp[v][p2]) {
- lr.push_back(v); p1 = v;
- } else {
- rl.push_back(v); p2 = v;
- }}
- lr.insert(lr.end(), rl.rbegin(), rl.rend());
- // Enthält Knoten 0 zweimal. An erster und letzter Position.
- // return lr;
-}
diff --git a/graph/blossom.cpp b/graph/blossom.cpp
deleted file mode 100644
index 7bd494a..0000000
--- a/graph/blossom.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-struct GM {
- vector<vector<int>> adj;
- // pairs ist der gematchte knoten oder n
- vector<int> pairs, first, que;
- vector<pair<int, int>> label;
- int head, tail;
-
- GM(int n) : adj(n), pairs(n + 1, n), first(n + 1, n),
- que(n), label(n + 1, {-1, -1}) {}
-
- void rematch(int u, int v) {
- int t = pairs[u]; pairs[u] = v;
- if (pairs[t] != u) return;
- if (label[u].second == -1) {
- pairs[t] = label[u].first;
- rematch(pairs[t], t);
- } else {
- auto [x, y] = label[u];
- rematch(x, y);
- rematch(y, x);
- }}
-
- int findFirst(int v) {
- return label[first[v]].first < 0 ? first[v]
- : first[v] = findFirst(first[v]);
- }
-
- void relabel(int x, int y) {
- int r = findFirst(x);
- int s = findFirst(y);
- if (r == s) return;
- auto h = label[r] = label[s] = {~x, y};
- int join;
- while (true) {
- if (s != sz(adj)) swap(r, s);
- r = findFirst(label[pairs[r]].first);
- if (label[r] == h) {
- join = r;
- break;
- } else {
- label[r] = h;
- }}
- for (int v : {first[x], first[y]}) {
- for (; v != join; v = first[label[pairs[v]].first]) {
- label[v] = {x, y};
- first[v] = join;
- que[tail++] = v;
- }}}
-
- bool augment(int v) {
- label[v] = {sz(adj), -1};
- first[v] = sz(adj);
- head = tail = 0;
- for (que[tail++] = v; head < tail;) {
- int x = que[head++];
- for (int y : adj[x]) {
- if (pairs[y] == sz(adj) && y != v) {
- pairs[y] = x;
- rematch(x, y);
- return true;
- } else if (label[y].first >= 0) {
- relabel(x, y);
- } else if (label[pairs[y]].first == -1) {
- label[pairs[y]].first = x;
- first[pairs[y]] = y;
- que[tail++] = pairs[y];
- }}}
- return false;
- }
-
- int match() {
- int matching = head = tail = 0;
- for (int v = 0; v < sz(adj); v++) {
- if (pairs[v] < sz(adj) || !augment(v)) continue;
- matching++;
- for (int i = 0; i < tail; i++)
- label[que[i]] = label[pairs[que[i]]] = {-1, -1};
- label[sz(adj)] = {-1, -1};
- }
- return matching;
- }
-};
diff --git a/graph/bronKerbosch.cpp b/graph/bronKerbosch.cpp
deleted file mode 100644
index ceeb668..0000000
--- a/graph/bronKerbosch.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-using bits = bitset<64>;
-vector<bits> adj, cliques;
-
-void addEdge(int a, int b) {
- if (a != b) adj[a][b] = adj[b][a] = 1;
-}
-
-void bronKerboschRec(bits R, bits P, bits X) {
- if (!P.any() && !X.any()) {
- cliques.push_back(R);
- } else {
- int q = min(P._Find_first(), X._Find_first());
- bits cands = P & ~adj[q];
- for (int i = 0; i < sz(adj); i++) if (cands[i]){
- R[i] = 1;
- bronKerboschRec(P & adj[i], X & adj[i], R);
- R[i] = P[i] = 0;
- X[i] = 1;
-}}}
-
-void bronKerbosch() {
- cliques.clear();
- bronKerboschRec({}, {(1ull << sz(adj)) - 1}, {});
-}
diff --git a/graph/capacityScaling.cpp b/graph/capacityScaling.cpp
deleted file mode 100644
index 90ae654..0000000
--- a/graph/capacityScaling.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-struct edge {
- int from, to;
- ll f, c;
-};
-
-vector<edge> edges;
-vector<vector<int>> adj;
-int s, t, dfsCounter;
-vector<int> visited;
-ll capacity;
-
-void addEdge(int from, int to, ll c) {
- adj[from].push_back(sz(edges));
- edges.push_back({from, to, 0, c});
- adj[to].push_back(sz(edges));
- edges.push_back({to, from, 0, 0});
-}
-
-bool dfs(int v) {
- if (v == t) return true;
- if (visited[v] == dfsCounter) return false;
- visited[v] = dfsCounter;
- for (int id : adj[v]) {
- if (edges[id].c >= capacity && dfs(edges[id].to)) {
- edges[id].c -= capacity; edges[id ^ 1].c += capacity;
- edges[id].f += capacity; edges[id ^ 1].f -= capacity;
- return true;
- }}
- return false;
-}
-
-ll maxFlow(int source, int target) {
- capacity = 1ll << 62;
- s = source;
- t = target;
- ll flow = 0;
- visited.assign(sz(adj), 0);
- dfsCounter = 0;
- while (capacity) {
- while (dfsCounter++, dfs(s)) flow += capacity;
- capacity /= 2;
- }
- return flow;
-}
diff --git a/graph/centroid.cpp b/graph/centroid.cpp
deleted file mode 100644
index 2494464..0000000
--- a/graph/centroid.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-vector<int> s;
-void dfs_sz(int v, int from = -1) {
- s[v] = 1;
- for (int u : adj[v]) if (u != from) {
- dfs_sz(u, v);
- s[v] += s[u];
-}}
-
-pair<int, int> dfs_cent(int v, int from, int n) {
- for (int u : adj[v]) if (u != from) {
- if (2 * s[u] == n) return {v, u};
- if (2 * s[u] > n) return dfs_cent(u, v, n);
- }
- return {v, -1};
-}
-
-pair<int, int> find_centroid(int root) {
- s.resize(sz(adj));
- dfs_sz(root);
- return dfs_cent(root, -1, s[root]);
-}
diff --git a/graph/connect.cpp b/graph/connect.cpp
deleted file mode 100644
index 98b5b25..0000000
--- a/graph/connect.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-struct connect {
- int n;
- vector<pair<int, int>> edges;
- LCT lct; // min LCT no updates required
-
- connect(int n, int m) : n(n), edges(m), lct(n+m) {}
-
- bool connected(int u, int v) {
- return lct.connected(&lct.nodes[u], &lct.nodes[v]);
- }
-
- void addEdge(int u, int v, int id) {
- lct.nodes[id + n] = LCT::Node(id + n, id + n);
- edges[id] = {u, v};
- if (connected(u, v)) {
- int old = lct.query(&lct.nodes[u], &lct.nodes[v]);
- if (old < id) eraseEdge(old);
- }
- if (!connected(u, v)) {
- lct.link(&lct.nodes[u], &lct.nodes[id + n]);
- lct.link(&lct.nodes[v], &lct.nodes[id + n]);
- }}
-
- void eraseEdge(ll id) {
- if (connected(edges[id].first, edges[id].second) &&
- lct.query(&lct.nodes[edges[id].first],
- &lct.nodes[edges[id].second]) == id) {
- lct.cut(&lct.nodes[edges[id].first], &lct.nodes[id + n]);
- lct.cut(&lct.nodes[edges[id].second], &lct.nodes[id + n]);
- }}
-};
diff --git a/graph/cycleCounting.cpp b/graph/cycleCounting.cpp
deleted file mode 100644
index 00ecc3a..0000000
--- a/graph/cycleCounting.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-constexpr int maxEdges = 128;
-using cycle = bitset<maxEdges>;
-struct cycles {
- vector<vector<pair<int, int>>> adj;
- vector<bool> seen;
- vector<cycle> paths, base;
- vector<pair<int, int>> edges;
-
- cycles(int n) : adj(n), seen(n), paths(n) {}
-
- void addEdge(int u, int v) {
- adj[u].push_back({v, sz(edges)});
- adj[v].push_back({u, sz(edges)});
- edges.push_back({u, v});
- }
-
- void addBase(cycle cur) {
- for (cycle o : base) {
- o ^= cur;
- if (o._Find_first() > cur._Find_first()) cur = o;
- }
- if (cur.any()) base.push_back(cur);
- }
-
- void findBase(int v = 0, int from = -1, cycle cur = {}) {
- if (adj.empty()) return;
- if (seen[v]) {
- addBase(cur ^ paths[v]);
- } else {
- seen[v] = true;
- paths[v] = cur;
- for (auto [u, id] : adj[v]) {
- if (u == from) continue;
- cur[id].flip();
- findBase(u, v, cur);
- cur[id].flip();
- }}}
-
- //cycle must be constrcuted from base
- bool isCycle(cycle cur) {
- if (cur.none()) return false;
- init(sz(adj)); // union find @\sourceref{datastructures/unionFind.cpp}@
- for (int i = 0; i < sz(edges); i++) {
- if (cur[i]) {
- cur[i] = false;
- if (findSet(edges[i].first) ==
- findSet(edges[i].second)) break;
- unionSets(edges[i].first, edges[i].second);
- }}
- return cur.none();
- };
-
- int count() {
- findBase();
- int res = 0;
- for (int i = 1; i < (1 << sz(base)); i++) {
- cycle cur;
- for (int j = 0; j < sz(base); j++) {
- if (((i >> j) & 1) != 0) cur ^= base[j];
- if (isCycle(cur)) res++;
- }
- return res;
- }
-};
diff --git a/graph/dfs.tex b/graph/dfs.tex
deleted file mode 100644
index 1e6705f..0000000
--- a/graph/dfs.tex
+++ /dev/null
@@ -1,16 +0,0 @@
-\begin{expandtable}
-\begin{tabularx}{\linewidth}{|X|XIXIX|}
- \hline
- Kantentyp $(v, w)$ & \code{dfs[v] < dfs[w]} & \code{fin[v] > fin[w]} & \code{seen[w]} \\
- %$(v, w)$ & \code{dfs[w]} & \code{fin[w]} & \\
- \hline
- in-tree & \code{true} & \code{true} & \code{false} \\
- \grayhline
- forward & \code{true} & \code{true} & \code{true} \\
- \grayhline
- backward & \code{false} & \code{false} & \code{true} \\
- \grayhline
- cross & \code{false} & \code{true} & \code{true} \\
- \hline
-\end{tabularx}
-\end{expandtable}
diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
deleted file mode 100644
index 57071b0..0000000
--- a/graph/dijkstra.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-using path = pair<ll, int>; //dist, destination
-
-void dijkstra(const vector<vector<path>>& adj, int start) {
- priority_queue<path, vector<path>, greater<path>> pq;
- vector<ll> dist(sz(adj), INF);
- vector<int> prev(sz(adj), -1);
- dist[start] = 0; pq.emplace(0, start);
-
- while (!pq.empty()) {
- auto [dv, v] = pq.top(); pq.pop();
- if (dv > dist[v]) continue; // WICHTIG!
-
- for (auto [du, u] : adj[v]) {
- ll newDist = dv + du;
- if (newDist < dist[u]) {
- dist[u] = newDist;
- prev[u] = v;
- pq.emplace(dist[u], u);
- }}}
- //return dist, prev;
-}
diff --git a/graph/dinicScaling.cpp b/graph/dinicScaling.cpp
deleted file mode 100644
index f4e833a..0000000
--- a/graph/dinicScaling.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-struct Edge {
- int to, rev;
- ll f, c;
-};
-
-vector<vector<Edge>> adj;
-int s, t;
-vector<int> pt, dist;
-
-void addEdge(int u, int v, ll c) {
- adj[u].push_back({v, (int)sz(adj[v]), 0, c});
- adj[v].push_back({u, (int)sz(adj[u]) - 1, 0, 0});
-}
-
-bool bfs(ll lim) {
- dist.assign(sz(adj), -1);
- dist[s] = 0;
- queue<int> q({s});
- while (!q.empty() && dist[t] < 0) {
- int v = q.front(); q.pop();
- for (Edge& e : adj[v]) {
- if (dist[e.to] < 0 && e.c - e.f >= lim) {
- dist[e.to] = dist[v] + 1;
- q.push(e.to);
- }}}
- return dist[t] >= 0;
-}
-
-bool dfs(int v, ll flow) {
- if (v == t) return true;
- for (; pt[v] < sz(adj[v]); pt[v]++) {
- Edge& e = adj[v][pt[v]];
- if (dist[e.to] != dist[v] + 1) continue;
- if (e.c - e.f >= flow && dfs(e.to, flow)) {
- e.f += flow;
- adj[e.to][e.rev].f -= flow;
- return true;
- }}
- return false;
-}
-
-ll maxFlow(int source, int target) {
- s = source, t = target;
- ll flow = 0;
- for (ll lim = (1LL << 62); lim >= 1; lim /= 2) {
- while (bfs(lim)) {
- pt.assign(sz(adj), 0);
- while (dfs(s, lim)) flow += lim;
- }}
- return flow;
-}
diff --git a/graph/euler.cpp b/graph/euler.cpp
deleted file mode 100644
index a5ea192..0000000
--- a/graph/euler.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-vector<vector<int>> idx;
-vector<int> to, validIdx, cycle;
-vector<bool> used;
-
-void addEdge(int u, int v) {
- idx[u].push_back(sz(to));
- to.push_back(v);
- used.push_back(false);
- idx[v].push_back(sz(to)); // für ungerichtet
- to.push_back(u);
- used.push_back(false);
-}
-
-void euler(int v) { // init idx und validIdx
- for (;validIdx[v] < sz(idx[v]); validIdx[v]++) {
- if (!used[idx[v][validIdx[v]]]) {
- int u = to[idx[v][validIdx[v]]];
- used[idx[v][validIdx[v]]] = true;
- used[idx[v][validIdx[v]] ^ 1] = true; // für ungerichtet
- euler(u);
- }}
- cycle.push_back(v); // Zyklus in umgekehrter Reihenfolge.
-}
diff --git a/graph/floydWarshall.cpp b/graph/floydWarshall.cpp
deleted file mode 100644
index fb6263e..0000000
--- a/graph/floydWarshall.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-vector<vector<ll>> dist; // Entfernung zwischen je zwei Punkten.
-vector<vector<int>> pre;
-
-void floydWarshall() {
- pre.assign(sz(dist), vector<int>(sz(dist), -1));
- for (int i = 0; i < sz(dist); i++) {
- for (int j = 0; j < sz(dist); j++) {
- if (dist[i][j] < INF) {
- pre[i][j] = j;
- }}}
-
- for (int k = 0; k < sz(dist); k++) {
- for (int i = 0; i < sz(dist); i++) {
- for (int j = 0; j < sz(dist); j++) {
- if (dist[i][j] > dist[i][k] + dist[k][j]) {
- dist[i][j] = dist[i][k] + dist[k][j];
- pre[i][j] = pre[i][k];
-}}}}}
-
-vector<int> getPath(int u, int v) {
- //return dist[u][v]; // Pfadlänge u -> v
- if (pre[u][v] < 0) return {};
- vector<int> path = {v};
- while (u != v) path.push_back(u = pre[u][v]);
- return path; //Pfad u -> v
-}
diff --git a/graph/graph.tex b/graph/graph.tex
deleted file mode 100644
index 9a0dc24..0000000
--- a/graph/graph.tex
+++ /dev/null
@@ -1,285 +0,0 @@
-\section{Graphen}
-
-\begin{algorithm}{Minimale Spannbäume}
- \paragraph{Schnitteigenschaft}
- Für jeden Schnitt $C$ im Graphen gilt:
- Gibt es eine Kante $e$, die echt leichter ist als alle anderen Schnittkanten, so gehört diese zu allen minimalen Spannbäumen.
- ($\Rightarrow$ Die leichteste Kante in einem Schnitt kann in einem minimalen Spannbaum verwendet werden.)
-
- \paragraph{Kreiseigenschaft}
- Für jeden Kreis $K$ im Graphen gilt:
- Die schwerste Kante auf dem Kreis ist nicht Teil des minimalen Spannbaums.
-
- \subsection{\textsc{Kruskal}}
- \begin{methods}[ll]
- berechnet den Minimalen Spannbaum & \runtime{\abs{E}\cdot\log(\abs{E})} \\
- \end{methods}
- \sourcecode{graph/kruskal.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Heavy-Light Decomposition}
- \begin{methods}
- \method{get\_intervals}{gibt Zerlegung des Pfades von $u$ nach $v$}{\log(\abs{V})}
- \end{methods}
- \textbf{Wichtig:} Intervalle sind halboffen
-
- Subbaum unter dem Knoten $v$ ist das Intervall $[\text{\code{in[v]}},~\text{\code{out[v]}})$.
- \sourcecode{graph/hld.cpp}
-\end{algorithm}
-
-\begin{algorithm}[optional]{Lowest Common Ancestor}
- \begin{methods}
- \method{init}{baut DFS-Baum über $g$ auf}{\abs{V}\*\log(\abs{V})}
- \method{getLCA}{findet LCA}{1}
- \method{getDepth}{berechnet Distanz zur Wurzel im DFS-Baum}{1}
- \end{methods}
- \sourcecode{graph/LCA_sparse.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Binary Lifting}
- % https://codeforces.com/blog/entry/74847
- \begin{methods}
- \method{Lift}{constructor}{\abs{V}}
- \method{depth}{distance to root of vertex $v$}{1}
- \method{lift}{vertex above $v$ at depth $d$}{\log(\abs{V})}
- \method{lca}{lowest common ancestor of $u$ and $v$}{\log(\abs{V})}
- \end{methods}
- \sourcecode{graph/binary_lifting.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Centroids}
- \begin{methods}
- \method{find\_centroid}{findet alle Centroids des Baums (maximal 2)}{\abs{V}}
- \end{methods}
- \sourcecode{graph/centroid.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Eulertouren}
- \begin{methods}
- \method{euler}{berechnet den Kreis}{\abs{V}+\abs{E}}
- \end{methods}
- \sourcecode{graph/euler.cpp}
- \begin{itemize}
- \item Zyklus existiert, wenn jeder Knoten geraden Grad hat (ungerichtet),\\ bei jedem Knoten Ein- und Ausgangsgrad übereinstimmen (gerichtet).
- \item Pfad existiert, wenn genau $\{0, 2\}$ Knoten ungeraden Grad haben (ungerichtet),\\ bei allen Knoten Ein- und Ausgangsgrad übereinstimmen oder einer eine Ausgangskante mehr hat (Startknoten) und einer eine Eingangskante mehr hat (Endknoten).
- \item \textbf{Je nach Aufgabenstellung überprüfen, wie ein unzusammenhängender Graph interpretiert werden sollen.}
- \item Wenn eine bestimmte Sortierung verlangt wird oder Laufzeit vernachlässigbar ist, ist eine Implementierung mit einem \code{vector<set<int>> adj} leichter
- \item \textbf{Wichtig:} Algorithmus schlägt nicht fehl, falls kein Eulerzyklus existiert.
- Die Existenz muss separat geprüft werden.
- \end{itemize}
-\end{algorithm}
-
-\begin{algorithm}{Baum-Isomorphie}
- \begin{methods}
- \method{treeLabel}{berechnet kanonischen Namen für einen Baum}{\abs{V}\*\log(\abs{V})}
- \end{methods}
- \sourcecode{graph/treeIsomorphism.cpp}
-\end{algorithm}
-
-\subsection{Kürzeste Wege}
-
-\subsubsection{\textsc{Bellmann-Ford}-Algorithmus}
-\method{bellmanFord}{kürzeste Pfade oder negative Kreise finden}{\abs{V}\*\abs{E}}
-\sourcecode{graph/bellmannFord.cpp}
-
-\subsubsection{Algorithmus von \textsc{Dijkstra}}
-\method{dijkstra}{kürzeste Pfade in Graphen ohne negative Kanten}{\abs{E}\*\log(\abs{V})}
-\sourcecode{graph/dijkstra.cpp}
-
-\subsubsection{\textsc{Floyd-Warshall}-Algorithmus}
-\method{floydWarshall}{kürzeste Pfade oder negative Kreise finden}{\abs{V}^3}
-\begin{itemize}
- \item \code{dist[i][i] = 0, dist[i][j] = edge\{j, j\}.weight} oder \code{INF}
- \item \code{i} liegt auf einem negativen Kreis $\Leftrightarrow$ \code{dist[i][i] < 0}.
-\end{itemize}
-\sourcecode{graph/floydWarshall.cpp}
-
-\subsubsection{Matrix-Algorithmus}
-Sei $d_{i\smash{j}}$ die Distanzmatrix von $G$, dann gibt $d_{i\smash{j}}^k$ die kürzeste Distanz von $i$ nach $j$ mit maximal $k$ kanten an mit der Verknüpfung: $c_{i\smash{j}} = a_{i\smash{j}} \otimes b_{i\smash{j}} = \min\{a_{ik} \cdot b_{k\smash{j}}\}$
-
-
-Sei $a_{ij}$ die Adjazenzmatrix von $G$ \textcolor{gray}{(mit $a_{ii} = 1$)}, dann gibt $a_{i\smash{j}}^k$ die Anzahl der Wege von $i$ nach $j$ mit Länge genau \textcolor{gray}{(maximal)} $k$ an mit der Verknüpfung: $c_{i\smash{j}} = a_{i\smash{j}} \otimes b_{i\smash{j}} = \sum a_{ik} \cdot b_{k\smash{j}}$
-
-\begin{algorithm}{Dynamic Connectivity}
- \begin{methods}
- \method{Constructor}{erzeugt Baum ($n$ Knoten, $m$ updates)}{n+m}
- \method{addEdge}{fügt Kannte ein,\code{id}=delete Zeitpunkt}{\log(n)}
- \method{eraseEdge}{entfernt Kante \code{id}}{\log(n)}
- \end{methods}
- \sourcecode{graph/connect.cpp}
-\end{algorithm}
-
-\begin{algorithm}{\textsc{Erd\H{o}s-Gallai}}
- Sei $d_1 \geq \cdots \geq d_{n}$. Es existiert genau dann ein Graph $G$ mit Degreesequence $d$ falls $\sum\limits_{i=1}^{n} d_i$ gerade ist und für $1\leq k \leq n$: $\sum\limits_{i=1}^{k} d_i \leq k\cdot(k-1)+\sum\limits_{i=k+1}^{n} \min(d_i, k)$
- \begin{methods}
- \method{havelHakimi}{findet Graph}{(\abs{V}+\abs{E})\cdot\log(\abs{V})}
- \end{methods}
- \sourcecode{graph/havelHakimi.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Strongly Connected Components (\textsc{Tarjan})}
- \begin{methods}
- \method{scc}{berechnet starke Zusammenhangskomponenten}{\abs{V}+\abs{E}}
- \end{methods}
- \sourcecode{graph/scc.cpp}
-\end{algorithm}
-
-\begin{algorithm}{DFS}
- \input{graph/dfs}
-\end{algorithm}
-
-\begin{algorithm}{Artikulationspunkte, Brücken und BCC}
- \begin{methods}
- \method{find}{berechnet Artikulationspunkte, Brücken und BCC}{\abs{V}+\abs{E}}
- \end{methods}
- \textbf{Wichtig:} isolierte Knoten und Brücken sind keine BCC.
- \sourcecode{graph/articulationPoints.cpp}
-\end{algorithm}
-
-\begin{algorithm}{2-SAT}
- \sourcecode{graph/2sat.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Maximal Cliques}
- \begin{methods}
- \method{bronKerbosch}{berechnet alle maximalen Cliquen}{3^\frac{n}{3}}
- \method{addEdge}{fügt \textbf{ungerichtete} Kante ein}{1}
- \end{methods}
- \sourcecode{graph/bronKerbosch.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Cycle Counting}
- \begin{methods}
- \method{findBase}{berechnet Basis}{\abs{V}\cdot\abs{E}}
- \method{count}{zählt Zykel}{2^{\abs{\mathit{base}}}}
- \end{methods}
- \begin{itemize}
- \item jeder Zyklus ist das xor von einträgen in \code{base}.
- \end{itemize}
- \sourcecode{graph/cycleCounting.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Wert des maximalen Matchings}
- Fehlerwahrscheinlichkeit: $\left(\frac{m}{MOD}\right)^I$
- \sourcecode{graph/matching.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Allgemeines maximales Matching}
- \begin{methods}
- \method{match}{berechnet algemeines Matching}{\abs{E}\*\abs{V}\*\log(\abs{V})}
- \end{methods}
- \sourcecode{graph/blossom.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Rerooting Template}
- \sourcecode{graph/reroot.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Virtual Trees}
- \sourcecode{graph/virtualTree.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Maximum Cardinality Bipartite Matching}
- \label{kuhn}
- \begin{methods}
- \method{kuhn}{berechnet Matching}{\abs{V}\*\min(ans^2, \abs{E})}
- \end{methods}
- \begin{itemize}
- \item die ersten [0..l) Knoten in \code{adj} sind die linke Seite des Graphen
- \end{itemize}
- \sourcecode{graph/maxCarBiMatch.cpp}
- \begin{methods}
- \method{hopcroft\_karp}{berechnet Matching}{\sqrt{\abs{V}}\*\abs{E}}
- \end{methods}
- \sourcecode{graph/hopcroftKarp.cpp}
-\end{algorithm}
-
-\begin{algorithm}{Global Mincut}
- \begin{methods}
- \method{stoer\_wagner}{berechnet globalen Mincut}{\abs{V}\abs{E}+\abs{V}^2\*\log(\abs{E})}
- \method{merge(a,b)}{merged Knoten $b$ in Knoten $a$}{\abs{E}}
- \end{methods}
- \textbf{Tipp:} Cut Rekonstruktion mit \code{unionFind} für Partitionierung oder \code{vector<bool>} für edge id's im cut.
- \sourcecode{graph/stoerWagner.cpp}
-\end{algorithm}
-
-\subsection{Max-Flow}
-\optional{
-\subsubsection{Capacity Scaling \opthint}
-\begin{methods}
- \method{maxFlow}{gut bei dünn besetzten Graphen.}{\abs{E}^2\*\log(C)}
- \method{addEdge}{fügt eine \textbf{gerichtete} Kante ein}{1}
-\end{methods}
-\sourcecode{graph/capacityScaling.cpp}
-}
-
-\optional{
-\subsubsection{Push Relabel \opthint}
-\begin{methods}
- \method{maxFlow}{gut bei sehr dicht besetzten Graphen.}{\abs{V}^2\*\sqrt{\abs{E}}}
- \method{addEdge}{fügt eine \textbf{gerichtete} Kante ein}{1}
-\end{methods}
-\sourcecode{graph/pushRelabel.cpp}
-}
-
-\subsubsection{\textsc{Dinic}'s Algorithm mit Capacity Scaling}
-\begin{methods}
- \method{maxFlow}{doppelt so schnell wie \textsc{Ford-Fulkerson}}{\abs{V}^2\cdot\abs{E}}
- \method{addEdge}{fügt eine \textbf{gerichtete} Kante ein}{1}
-\end{methods}
-\sourcecode{graph/dinicScaling.cpp}
-
-\begin{algorithm}{Min-Cost-Max-Flow}
- \begin{methods}
- \method{mincostflow}{berechnet Fluss}{\abs{V}^2\cdot\abs{E}^2}
- \end{methods}
- \sourcecode{graph/minCostMaxFlow.cpp}
-\end{algorithm}
-\columnbreak
-
-\optional{
-\subsubsection{Anwendungen \opthint}
-\begin{itemize}
- \item \textbf{Maximum Edge Disjoint Paths}\newline
- Finde die maximale Anzahl Pfade von $s$ nach $t$, die keine Kante teilen.
- \begin{enumerate}
- \item Setze $s$ als Quelle, $t$ als Senke und die Kapazität jeder Kante auf 1.
- \item Der maximale Fluss entspricht den unterschiedlichen Pfaden ohne gemeinsame Kanten.
- \end{enumerate}
- \item \textbf{Maximum Independent Paths}\newline
- Finde die maximale Anzahl an Pfaden von $s$ nach $t$, die keinen Knoten teilen.
- \begin{enumerate}
- \item Setze $s$ als Quelle, $t$ als Senke und die Kapazität jeder Kante \emph{und jedes Knotens} auf 1.
- \item Der maximale Fluss entspricht den unterschiedlichen Pfaden ohne gemeinsame Knoten.
- \end{enumerate}
- \item \textbf{Min-Cut}\newline
- Der maximale Fluss ist gleich dem minimalen Schnitt.
- Bei Quelle $s$ und Senke $t$, partitioniere in $S$ und $T$.
- Zu $S$ gehören alle Knoten, die im Residualgraphen von $s$ aus erreichbar sind (Rückwärtskanten beachten).
-\end{itemize}
-}
-
-\begin{algorithm}{Maximum Weight Bipartite Matching}
- \begin{methods}
- \method{match}{berechnet Matching}{\abs{V}^3}
- \end{methods}
- \sourcecode{graph/maxWeightBipartiteMatching.cpp}
-\end{algorithm}
-\vfill\null
-\columnbreak
-
-
-\begin{algorithm}[optional]{TSP}
- \begin{methods}
- \method{TSP}{berechnet eine Tour}{n^2\*2^n}
- \end{methods}
- \sourcecode{graph/TSP.cpp}
-\end{algorithm}
-
-\begin{algorithm}[optional]{Bitonic TSP}
- \begin{methods}
- \method{bitonicTSP}{berechnet eine Bitonische Tour}{n^2}
- \end{methods}
- \sourcecode{graph/bitonicTSPsimple.cpp}
-\end{algorithm}
-
diff --git a/graph/havelHakimi.cpp b/graph/havelHakimi.cpp
deleted file mode 100644
index cbd6991..0000000
--- a/graph/havelHakimi.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-vector<vector<int>> havelHakimi(const vector<int>& deg) {
- priority_queue<pair<int, int>> pq;
- for (int i = 0; i < sz(deg); i++) {
- if (deg[i] > 0) pq.push({deg[i], i});
- }
- vector<vector<int>> adj;
- while (!pq.empty()) {
- auto [degV, v] = pq.top(); pq.pop();
- if (sz(pq) < degV) return {}; //impossible
- vector<pair<int, int>> todo(degV);
- for (auto& e : todo) e = pq.top(), pq.pop();
- for (auto [degU, u] : todo) {
- adj[v].push_back(u);
- adj[u].push_back(v);
- if (degU > 1) pq.push({degU - 1, u});
- }}
- return adj;
-}
diff --git a/graph/hld.cpp b/graph/hld.cpp
deleted file mode 100644
index 65d3f5c..0000000
--- a/graph/hld.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-vector<vector<int>> adj;
-vector<int> sz, in, out, nxt, par;
-int counter;
-
-void dfs_sz(int v = 0, int from = -1) {
- for (auto& u : adj[v]) if (u != from) {
- dfs_sz(u, v);
- sz[v] += sz[u];
- if (adj[v][0] == from || sz[u] > sz[adj[v][0]]) {
- swap(u, adj[v][0]); //changes adj!
-}}}
-
-void dfs_hld(int v = 0, int from = -1) {
- par[v] = from;
- in[v] = counter++;
- for (int u : adj[v]) if (u != from) {
- nxt[u] = (u == adj[v][0]) ? nxt[v] : u;
- dfs_hld(u, v);
- }
- out[v] = counter;
-}
-
-void init(int root = 0) {
- int n = sz(adj);
- sz.assign(n, 1), nxt.assign(n, root), par.assign(n, -1);
- in.resize(n), out.resize(n);
- counter = 0;
- dfs_sz(root);
- dfs_hld(root);
-}
-
-template<typename F>
-void for_intervals(int u, int v, F&& f) {
- for (;; v = par[nxt[v]]) {
- if (in[v] < in[u]) swap(u, v);
- f(max(in[u], in[nxt[v]]), in[v] + 1);
- if (in[nxt[v]] <= in[u]) return;
-}}
-
-int get_lca(int u, int v) {
- for (;; v = par[nxt[v]]) {
- if (in[v] < in[u]) swap(u, v);
- if (in[nxt[v]] <= in[u]) return u;
-}}
diff --git a/graph/hopcroftKarp.cpp b/graph/hopcroftKarp.cpp
deleted file mode 100644
index c1f5d1c..0000000
--- a/graph/hopcroftKarp.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-vector<vector<int>> adj;
-// pairs ist der gematchte Knoten oder -1
-vector<int> pairs, dist, ptr;
-
-bool bfs(int l) {
- queue<int> q;
- for(int v = 0; v < l; v++) {
- if (pairs[v] < 0) {dist[v] = 0; q.push(v);}
- else dist[v] = -1;
- }
- bool exist = false;
- while(!q.empty()) {
- int v = q.front(); q.pop();
- for (int u : adj[v]) {
- if (pairs[u] < 0) {exist = true; continue;}
- if (dist[pairs[u]] < 0) {
- dist[pairs[u]] = dist[v] + 1;
- q.push(pairs[u]);
- }}}
- return exist;
-}
-
-bool dfs(int v) {
- for (; ptr[v] < sz(adj[v]); ptr[v]++) {
- int u = adj[v][ptr[v]];
- if (pairs[u] < 0 ||
- (dist[pairs[u]] > dist[v] && dfs(pairs[u]))) {
- pairs[u] = v; pairs[v] = u;
- return true;
- }}
- return false;
-}
-
-int hopcroft_karp(int l) { // l = #Knoten links
- int ans = 0;
- pairs.assign(sz(adj), -1);
- dist.resize(l);
- // Greedy Matching, optionale Beschleunigung.
- for (int v = 0; v < l; v++) for (int u : adj[v])
- if (pairs[u] < 0) {pairs[u] = v; pairs[v] = u; ans++; break;}
- while(bfs(l)) {
- ptr.assign(l, 0);
- for(int v = 0; v < l; v++) {
- if (pairs[v] < 0) ans += dfs(v);
- }}
- return ans;
-}
diff --git a/graph/kruskal.cpp b/graph/kruskal.cpp
deleted file mode 100644
index 987d30b..0000000
--- a/graph/kruskal.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-sort(all(edges));
-vector<Edge> mst;
-ll cost = 0;
-for (Edge& e : edges) {
- if (findSet(e.from) != findSet(e.to)) {
- unionSets(e.from, e.to);
- mst.push_back(e);
- cost += e.cost;
-}}
diff --git a/graph/matching.cpp b/graph/matching.cpp
deleted file mode 100644
index 2513604..0000000
--- a/graph/matching.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-constexpr int MOD=1'000'000'007, I=10;
-vector<vector<ll>> adj, mat;
-
-int max_matching() {
- int ans = 0;
- mat.assign(sz(adj), {});
- for (int _ = 0; _ < I; _++) {
- for (int v = 0; v < sz(adj); v++) {
- mat[v].assign(sz(adj), 0);
- for (int u : adj[v]) {
- if (u < v) {
- mat[v][u] = rand() % (MOD - 1) + 1;
- mat[u][v] = MOD - mat[v][u];
- }}}
- gauss(sz(adj), MOD); //LGS @\sourceref{math/lgsFp.cpp}@
- int rank = 0;
- for (auto& row : mat) {
- if (*min_element(all(row)) != 0) rank++;
- }
- ans = max(ans, rank / 2);
- }
- return ans;
-}
diff --git a/graph/maxCarBiMatch.cpp b/graph/maxCarBiMatch.cpp
deleted file mode 100644
index e928387..0000000
--- a/graph/maxCarBiMatch.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-vector<vector<int>> adj;
-vector<int> pairs; // Der gematchte Knoten oder -1.
-vector<bool> visited;
-
-bool dfs(int v) {
- if (visited[v]) return false;
- visited[v] = true;
- for (int u : adj[v]) if (pairs[u] < 0 || dfs(pairs[u])) {
- pairs[u] = v; pairs[v] = u; return true;
- }
- return false;
-}
-
-int kuhn(int l) { // l = #Knoten links.
- pairs.assign(sz(adj), -1);
- int ans = 0;
- // Greedy Matching. Optionale Beschleunigung.
- for (int v = 0; v < l; v++) for (int u : adj[v])
- if (pairs[u] < 0) {pairs[u] = v; pairs[v] = u; ans++; break;}
- for (int v = 0; v < l; v++) if (pairs[v] < 0) {
- visited.assign(l, false);
- ans += dfs(v);
- }
- return ans; // Größe des Matchings.
-}
diff --git a/graph/maxWeightBipartiteMatching.cpp b/graph/maxWeightBipartiteMatching.cpp
deleted file mode 100644
index a2b0a80..0000000
--- a/graph/maxWeightBipartiteMatching.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-double costs[N_LEFT][N_RIGHT];
-
-// Es muss l<=r sein! (sonst Endlosschleife)
-double match(int l, int r) {
- vector<double> lx(l), ly(r);
- //xy is matching from l->r, yx from r->l, or -1
- vector<int> xy(l, -1), yx(r, -1);
- vector<pair<double, int>> slack(r);
-
- for (int x = 0; x < l; x++)
- lx[x] = *max_element(costs[x], costs[x] + r);
- for (int root = 0; root < l; root++) {
- vector<int> aug(r, -1);
- vector<bool> s(l);
- s[root] = true;
- for (int y = 0; y < r; y++) {
- slack[y] = {lx[root] + ly[y] - costs[root][y], root};
- }
- int y = -1;
- while (true) {
- double delta = INF;
- int x = -1;
- for (int yy = 0; yy < r; yy++) {
- if (aug[yy] < 0 && slack[yy].first < delta) {
- tie(delta, x) = slack[yy];
- y = yy;
- }}
- if (delta > 0) {
- for (int x = 0; x < l; x++) if (s[x]) lx[x] -= delta;
- for (int y = 0; y < r; y++) {
- if (aug[y] >= 0) ly[y] += delta;
- else slack[y].first -= delta;
- }}
- aug[y] = x;
- x = yx[y];
- if (x < 0) break;
- s[x] = true;
- for (int y = 0; y < r; y++) {
- if (aug[y] < 0) {
- double alt = lx[x] + ly[y] - costs[x][y];
- if (slack[y].first > alt) {
- slack[y] = {alt, x};
- }}}}
- while (y >= 0) {
- yx[y] = aug[y];
- swap(y, xy[aug[y]]);
- }}
- return accumulate(all(lx), 0.0) +
- accumulate(all(ly), 0.0); // Wert des Matchings
-}
diff --git a/graph/minCostMaxFlow.cpp b/graph/minCostMaxFlow.cpp
deleted file mode 100644
index 14a222c..0000000
--- a/graph/minCostMaxFlow.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-constexpr ll INF = 1LL << 60; // Größer als der maximale Fluss.
-struct MinCostFlow {
- struct edge {
- int to;
- ll f, cost;
- };
- vector<edge> edges;
- vector<vector<int>> adj;
- vector<int> pref, con;
- vector<ll> dist;
- const int s, t;
- ll maxflow, mincost;
-
- MinCostFlow(int n, int source, int target) :
- adj(n), s(source), t(target) {};
-
- void addEdge(int u, int v, ll c, ll cost) {
- adj[u].push_back(sz(edges));
- edges.push_back({v, c, cost});
- adj[v].push_back(sz(edges));
- edges.push_back({u, 0, -cost});
- }
-
- bool SPFA() {
- pref.assign(sz(adj), -1);
- dist.assign(sz(adj), INF);
- vector<bool> inqueue(sz(adj));
- queue<int> queue;
- dist[s] = 0;
- queue.push(s);
- pref[s] = s;
- inqueue[s] = true;
- while (!queue.empty()) {
- int cur = queue.front(); queue.pop();
- inqueue[cur] = false;
- for (int id : adj[cur]) {
- int to = edges[id].to;
- if (edges[id].f > 0 &&
- dist[to] > dist[cur] + edges[id].cost) {
- dist[to] = dist[cur] + edges[id].cost;
- pref[to] = cur;
- con[to] = id;
- if (!inqueue[to]) {
- inqueue[to] = true;
- queue.push(to);
- }}}}
- return pref[t] != -1;
- }
-
- void extend() {
- ll w = INF;
- for (int u = t; pref[u] != u; u = pref[u])
- w = min(w, edges[con[u]].f);
- maxflow += w;
- mincost += dist[t] * w;
- for (int u = t; pref[u] != u; u = pref[u]) {
- edges[con[u]].f -= w;
- edges[con[u] ^ 1].f += w;
- }}
-
- void mincostflow() {
- con.assign(sz(adj), 0);
- maxflow = mincost = 0;
- while (SPFA()) extend();
- }
-};
diff --git a/graph/pushRelabel.cpp b/graph/pushRelabel.cpp
deleted file mode 100644
index 904aec6..0000000
--- a/graph/pushRelabel.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-struct Edge {
- int to, rev;
- ll f, c;
-};
-
-vector<vector<Edge>> adj;
-vector<vector<int>> hs;
-vector<ll> ec;
-vector<int> cur, H;
-
-void addEdge(int u, int v, ll c) {
- adj[u].push_back({v, (int)sz(adj[v]), 0, c});
- adj[v].push_back({u, (int)sz(adj[u])-1, 0, 0});
-}
-
-void addFlow(Edge& e, ll f) {
- if (ec[e.to] == 0 && f > 0)
- hs[H[e.to]].push_back(e.to);
- e.f += f;
- adj[e.to][e.rev].f -= f;
- ec[e.to] += f;
- ec[adj[e.to][e.rev].to] -= f;
-}
-
-ll maxFlow(int s, int t) {
- int n = sz(adj);
- hs.assign(2*n, {});
- ec.assign(n, 0);
- cur.assign(n, 0);
- H.assign(n, 0);
- H[s] = n;
- ec[t] = 1;//never set t to active...
- vector<int> co(2*n);
- co[0] = n - 1;
- for (Edge& e : adj[s]) addFlow(e, e.c);
- for (int hi = 0;;) {
- while (hs[hi].empty()) if (!hi--) return -ec[s];
- int v = hs[hi].back();
- hs[hi].pop_back();
- while (ec[v] > 0) {
- if (cur[v] == sz(adj[v])) {
- H[v] = 2*n;
- for (int i = 0; i < sz(adj[v]); i++) {
- Edge& e = adj[v][i];
- if (e.c - e.f > 0 &&
- H[v] > H[e.to] + 1) {
- H[v] = H[e.to] + 1;
- cur[v] = i;
- }}
- co[H[v]]++;
- if (!--co[hi] && hi < n) {
- for (int i = 0; i < n; i++) {
- if (hi < H[i] && H[i] < n) {
- co[H[i]]--;
- H[i] = n + 1;
- }}}
- hi = H[v];
- } else {
- Edge& e = adj[v][cur[v]];
- if (e.c - e.f > 0 && H[v] == H[e.to] + 1) {
- addFlow(adj[v][cur[v]], min(ec[v], e.c - e.f));
- } else {
- cur[v]++;
-}}}}}
diff --git a/graph/reroot.cpp b/graph/reroot.cpp
deleted file mode 100644
index 4c6a748..0000000
--- a/graph/reroot.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Usual Tree DP can be broken down in 4 steps:
-// - Initialize dp[v] = identity
-// - Iterate over all children w and take a value for w
-// by looking at dp[w] and possibly the edge label of v -> w
-// - combine the values of those children
-// usually this operation should be commutative and associative
-// - finalize the dp[v] after iterating over all children
-struct Reroot {
- using T = ll;
-
- // identity element
- T E() {}
- // x: dp value of child
- // e: index of edge going to child
- T takeChild(T x, int e) {}
- T comb(T x, T y) {}
- // called after combining all dp values of children
- T fin(T x, int v) {}
-
- vector<vector<pair<int, int>>> g;
- vector<int> ord, pae;
- vector<T> dp;
-
- T dfs(int v) {
- ord.push_back(v);
- for (auto [w, e] : g[v]) {
- g[w].erase(find(all(g[w]), pair(v, e^1)));
- pae[w] = e^1;
- dp[v] = comb(dp[v], takeChild(dfs(w), e));
- }
- return dp[v] = fin(dp[v], v);
- }
-
- vector<T> solve(int n, vector<pair<int, int>> edges) {
- g.resize(n);
- for (int i = 0; i < n-1; i++) {
- g[edges[i].first].emplace_back(edges[i].second, 2*i);
- g[edges[i].second].emplace_back(edges[i].first, 2*i+1);
- }
- pae.assign(n, -1);
- dp.assign(n, E());
- dfs(0);
- vector<T> updp(n, E()), res(n, E());
- for (int v : ord) {
- vector<T> pref(sz(g[v])+1), suff(sz(g[v])+1);
- if (v != 0) pref[0] = takeChild(updp[v], pae[v]);
- for (int i = 0; i < sz(g[v]); i++){
- auto [u, w] = g[v][i];
- pref[i+1] = suff[i] = takeChild(dp[u], w);
- pref[i+1] = comb(pref[i], pref[i+1]);
- }
- for (int i = sz(g[v])-1; i >= 0; i--) {
- suff[i] = comb(suff[i], suff[i+1]);
- }
- for (int i = 0; i < sz(g[v]); i++) {
- updp[g[v][i].first] = fin(comb(pref[i], suff[i+1]), v);
- }
- res[v] = fin(pref.back(), v);
- }
- return res;
- }
-};
diff --git a/graph/scc.cpp b/graph/scc.cpp
deleted file mode 100644
index ac9a40b..0000000
--- a/graph/scc.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-vector<vector<int>> adj, sccs;
-int counter;
-vector<bool> inStack;
-vector<int> low, idx, s; //idx enthält Index der SCC pro Knoten.
-
-void visit(int v) {
- int old = low[v] = counter++;
- s.push_back(v); inStack[v] = true;
-
- for (auto u : adj[v]) {
- if (low[u] < 0) visit(u);
- if (inStack[u]) low[v] = min(low[v], low[u]);
- }
-
- if (old == low[v]) {
- sccs.push_back({});
- for (int u = -1; u != v;) {
- u = s.back(); s.pop_back(); inStack[u] = false;
- idx[u] = sz(sccs) - 1;
- sccs.back().push_back(u);
-}}}
-
-void scc() {
- inStack.assign(sz(adj), false);
- low.assign(sz(adj), -1);
- idx.assign(sz(adj), -1);
- sccs.clear();
-
- counter = 0;
- for (int i = 0; i < sz(adj); i++) {
- if (low[i] < 0) visit(i);
-}}
diff --git a/graph/stoerWagner.cpp b/graph/stoerWagner.cpp
deleted file mode 100644
index 97e667a..0000000
--- a/graph/stoerWagner.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-struct Edge {
- int from, to;
- ll cap;
-};
-
-vector<vector<Edge>> adj, tmp;
-vector<bool> erased;
-
-void merge(int u, int v) {
- tmp[u].insert(tmp[u].end(), all(tmp[v]));
- tmp[v].clear();
- erased[v] = true;
- for (auto& vec : tmp) {
- for (Edge& e : vec) {
- if (e.from == v) e.from = u;
- if (e.to == v) e.to = u;
-}}}
-
-ll stoer_wagner() {
- ll res = INF;
- tmp = adj;
- erased.assign(sz(tmp), false);
- for (int i = 1; i < sz(tmp); i++) {
- int s = 0;
- while (erased[s]) s++;
- priority_queue<pair<ll, int>> pq;
- pq.push({0, s});
- vector<ll> con(sz(tmp));
- ll cur = 0;
- vector<pair<ll, int>> state;
- while (!pq.empty()) {
- int c = pq.top().second;
- pq.pop();
- if (con[c] < 0) continue; //already seen
- con[c] = -1;
- for (auto e : tmp[c]) {
- if (con[e.to] >= 0) {//add edge to cut
- con[e.to] += e.cap;
- pq.push({con[e.to], e.to});
- cur += e.cap;
- } else if (e.to != c) {//remove edge from cut
- cur -= e.cap;
- }}
- state.push_back({cur, c});
- }
- int t = state.back().second;
- state.pop_back();
- if (state.empty()) return 0; //graph is not connected?!
- merge(state.back().second, t);
- res = min(res, state.back().first);
- }
- return res;
-}
diff --git a/graph/test/LCA_sparse.cpp b/graph/test/LCA_sparse.cpp
deleted file mode 100644
index c8b0017..0000000
--- a/graph/test/LCA_sparse.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "util.cpp"
-#define all(X) begin(X), end(X)
-#define sz ssize
-#include "../../datastructures/sparseTable.cpp"
-#include "../LCA_sparse.cpp"
-
-void test(vector<vector<int>> &adj, int root) {
- int n = adj.size();
-
- vector<int> parent(n);
- function<void(int,int)> dfs = [&](int u, int p) {
- parent[u] = p;
- for (int v: adj[u]) if (v != p) dfs(v, u);
- };
- dfs(root, -1);
-
- function<bool(int, int)> is_ancestor = [&](int u, int v) {
- while (v != -1 && u != v) v = parent[v];
- return u == v;
- };
- function<int(int)> depth = [&](int v) {
- int r = 0;
- while ((v = parent[v]) != -1) r++;
- return r;
- };
-
- LCA lca;
- lca.init(adj, root);
- for (int i = 0; i < n; i++) assert(lca.getDepth(i) == depth(i));
- for (int i = 0; i < 1000; i++) {
- int u = util::randint(n);
- int v = util::randint(n);
- int l = lca.getLCA(u, v);
- assert(is_ancestor(l, u));
- assert(is_ancestor(l, v));
- for (int p = parent[l]; int c: adj[l]) {
- if (c == p) continue;
- assert(!is_ancestor(c, u) || !is_ancestor(c, v));
- }
- }
-}
-
-int main() {
- {
- // Single vertex
- vector<vector<int>> adj(1);
- test(adj, 0);
- }
- {
- // Path
- vector<vector<int>> adj = util::path(100);
- int left = 0, mid = 40, right = 99;
- util::shuffle_graph(adj, left, mid, right);
- test(adj, left);
- test(adj, mid);
- test(adj, right);
- }
- {
- // Random
- vector<vector<int>> adj = util::random_tree(1000);
- test(adj, 0);
- }
-}
diff --git a/graph/test/binary_lifting.cpp b/graph/test/binary_lifting.cpp
deleted file mode 100644
index 05b903a..0000000
--- a/graph/test/binary_lifting.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "util.cpp"
-#include "../binary_lifting.cpp"
-
-void test(vector<vector<int>> &adj, int root) {
- int n = adj.size();
-
- vector<int> parent(n);
- function<void(int,int)> dfs = [&](int u, int p) {
- parent[u] = p;
- for (int v: adj[u]) if (v != p) dfs(v, u);
- };
- dfs(root, -1);
-
- function<bool(int, int)> is_ancestor = [&](int u, int v) {
- while (v != -1 && u != v) v = parent[v];
- return u == v;
- };
- function<int(int)> depth = [&](int v) {
- int r = 0;
- while ((v = parent[v]) != -1) r++;
- return r;
- };
-
- Lift lift(adj, root);
- for (int i = 0; i < n; i++) assert(lift.depth(i) == depth(i));
- for (int i = 0; i < 1000; i++) {
- int v = util::randint(n);
- int d = util::randint(n);
- int u = lift.lift(v, d);
- assert(is_ancestor(u, v));
- if (d <= depth(v)) assert(depth(u) == d);
- else assert(u == v);
- }
- for (int i = 0; i < 1000; i++) {
- int u = util::randint(n);
- int v = util::randint(n);
- int lca = lift.lca(u, v);
- assert(is_ancestor(lca, u));
- assert(is_ancestor(lca, v));
- for (int p = parent[lca]; int c: adj[lca]) {
- if (c == p) continue;
- assert(!is_ancestor(c, u) || !is_ancestor(c, v));
- }
- }
-}
-
-int main() {
- {
- // Single vertex
- vector<vector<int>> adj(1);
- test(adj, 0);
- }
- {
- // Path
- vector<vector<int>> adj = util::path(100);
- int left = 0, mid = 40, right = 99;
- util::shuffle_graph(adj, left, mid, right);
- test(adj, left);
- test(adj, mid);
- test(adj, right);
- }
- {
- // Random
- vector<vector<int>> adj = util::random_tree(1000);
- test(adj, 0);
- }
-}
diff --git a/graph/test/util.cpp b/graph/test/util.cpp
deleted file mode 100644
index 8c14b5c..0000000
--- a/graph/test/util.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-
-namespace util {
-
-void shuffle_adj_lists(vector<vector<int>> &adj) {
- for (auto &a: adj) ranges::shuffle(a, rd);
-}
-
-vector<vector<int>> random_tree(int n) {
- vector<vector<int>> adj(n);
-
- vector<vector<int>> components(n);
- for (int i = 0; i < n; i++) components[i].push_back(i);
- while (components.size() > 1) {
- int c1 = randint(components.size());
- int c2 = randint(components.size()-1);
- c2 += (c2 >= c1);
-
- int v1 = components[c1][randint(components[c1].size())];
- int v2 = components[c2][randint(components[c2].size())];
-
- adj[v1].push_back(v2);
- adj[v2].push_back(v1);
-
- if (components[c1].size() < components[c2].size()) swap(c1, c2);
- for (int v: components[c2]) components[c1].push_back(v);
- swap(components[c2], components.back());
- components.pop_back();
- }
-
- shuffle_adj_lists(adj);
- return adj;
-}
-
-vector<vector<int>> path(int n) {
- vector<vector<int>> adj(n);
- for (int i = 1; i < n; i++) {
- adj[i-1].push_back(i);
- adj[i].push_back(i-1);
- }
- return adj;
-}
-
-template<typename... Ts>
-void shuffle_graph(vector<vector<int>> &adj, Ts &...vertex) {
- int n = adj.size();
- vector<int> perm(n);
- iota(perm.begin(), perm.end(), 0);
- ranges::shuffle(perm, rd);
-
- vector<vector<int>> new_adj(n);
- for (int i = 0; i < n; i++) {
- auto &a = new_adj[perm[i]] = move(adj[i]);
- for (int &v: a) v = perm[v];
- }
- adj = move(new_adj);
- shuffle_adj_lists(adj);
- ((vertex = perm[vertex]), ...);
-}
-
-}
diff --git a/graph/treeIsomorphism.cpp b/graph/treeIsomorphism.cpp
deleted file mode 100644
index 4e9ddce..0000000
--- a/graph/treeIsomorphism.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-vector<vector<int>> adj;
-map<vector<int>, int> known;
-
-int treeLabel(int v, int from = -1) {
- vector<int> children;
- for (int u : adj[v]) {
- if (u == from) continue;
- children.push_back(treeLabel(u, v));
- }
- sort(all(children));
- if (known.find(children) == known.end()) {
- known[children] = sz(known);
- }
- return known[children];
-}
diff --git a/graph/virtualTree.cpp b/graph/virtualTree.cpp
deleted file mode 100644
index 2fcea80..0000000
--- a/graph/virtualTree.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// needs dfs in- and out- time and lca function
-vector<int> in, out;
-
-void virtualTree(vector<int> ind) { // indices of used nodes
- sort(all(ind), [&](int x, int y) {return in[x] < in[y];});
- for (int i=0; i<sz(a)-1; i++) {
- ind.push_back(lca(ind[i], ind[i+1]));
- }
- sort(all(ind), [&](int x, int y) {return in[x] < in[y];});
- ind.erase(unique(all(ind)), ind.end());
-
- int n = ind.size();
- vector<vector<int>> tree(n);
- vector<int> st = {0};
- for (int i=1; i<n; i++) {
- while (in[ind[i]] >= out[ind[st.back()]]) st.pop_back();
- tree[st.back()].push_back(i);
- st.push(i);
- }
- // virtual directed tree with n nodes, original indices in ind
- // weights can be calculated, e.g. with binary lifting
-}