From 49896415388748e7720e479ca460872e4e108c4e Mon Sep 17 00:00:00 2001 From: Triton Date: Tue, 15 Sep 2026 00:25:10 +0500 Subject: [PATCH] Add README --- DSU.h | 37 ++++++ Graph.h | 61 +++++++++ Graph_Euler.cpp | 146 +++++++++++++++++++++ Graph_Flow.cpp | 123 +++++++++++++++++ Graph_IO.cpp | 321 +++++++++++++++++++++++++++++++++++++++++++++ Graph_MST.cpp | 86 ++++++++++++ Graph_Matching.cpp | 61 +++++++++ README.md | 0 main.cpp | 24 ++++ 9 files changed, 859 insertions(+) create mode 100644 DSU.h create mode 100644 Graph.h create mode 100644 Graph_Euler.cpp create mode 100644 Graph_Flow.cpp create mode 100644 Graph_IO.cpp create mode 100644 Graph_MST.cpp create mode 100644 Graph_Matching.cpp create mode 100644 README.md create mode 100644 main.cpp diff --git a/DSU.h b/DSU.h new file mode 100644 index 0000000..ac612d2 --- /dev/null +++ b/DSU.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include + +struct DSU { + std::vector dsu_parent; + std::vector dsu_rank; + + DSU() {} + explicit DSU(int n) { init(n); } + + void init(int n) { + dsu_parent.resize(n + 1); + dsu_rank.assign(n + 1, 0); + for (int i = 0; i <= n; ++i) dsu_parent[i] = i; + } + + int find(int x) { + while (dsu_parent[x] != x) { + dsu_parent[x] = dsu_parent[dsu_parent[x]]; + x = dsu_parent[x]; + } + return x; + } + + bool unite(int a, int b) { + a = find(a); + b = find(b); + if (a == b) return false; + if (dsu_rank[a] < dsu_rank[b]) std::swap(a, b); + dsu_parent[b] = a; + if (dsu_rank[a] == dsu_rank[b]) ++dsu_rank[a]; + return true; + } + + bool same(int a, int b) { return find(a) == find(b); } +}; diff --git a/Graph.h b/Graph.h new file mode 100644 index 0000000..6f0de40 --- /dev/null +++ b/Graph.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include + +class Graph { +public: + Graph(); + explicit Graph(int n); + Graph(int n, bool directed, bool weighted, char form); + + int size() const { return n; } + bool isDirected() const { return directed; } + bool isWeighted() const { return weighted; } + char repr() const { return form; } + + void readGraph(std::string fileName); + void writeGraph(std::string fileName); + + void addEdge(int from, int to, int weight); + void removeEdge(int from, int to); + int changeEdge(int from, int to, int newWeight); + + void transformToAdjList(); + void transformToAdjMatrix(); + void transformToListOfEdges(); + + Graph getSpaingTreePrima() const; + Graph getSpaingTreeKruscal() const; + Graph getSpaingTreeBoruvka() const; + + int checkEuler(bool& circleExist) const; + std::vector getEuleranTourFleri() const; + std::vector getEuleranTourEffective() const; + + int checkBipart(std::vector& marks) const; + std::vector> getMaximumMatchingBipart() const; + + Graph flowFordFulkerson(int source, int sink) const; + Graph flowDinitz(int source, int sink) const; + +private: + int n = 0; + bool directed = false; + bool weighted = false; + char form = 'C'; + + std::vector> matrix; + std::vector>> adj; + std::vector> edges; + + bool hasEdge(int from, int to) const; + int weightOf(int from, int to) const; + + std::vector>> toAdjList() const; + std::vector> toMatrix() const; + std::vector> toEdgeList() const; + std::vector> toSimpleAdj() const; +}; diff --git a/Graph_Euler.cpp b/Graph_Euler.cpp new file mode 100644 index 0000000..ffb57cf --- /dev/null +++ b/Graph_Euler.cpp @@ -0,0 +1,146 @@ +#include "Graph.h" +#include "DSU.h" +#include +#include +#include + +static bool reachableWithoutEdge(const std::vector>>& g, + int from, int to, int a, int b, int w) { + std::vector visited(g.size(), 0); + std::stack st; + st.push(from); + visited[from] = 1; + while (!st.empty()) { + int u = st.top(); + st.pop(); + for (auto& e : g[u]) { + int v = e.first, ew = e.second; + if (u == a && v == b && ew == w) continue; + if (u == b && v == a && ew == w) continue; + if (!visited[v]) { + visited[v] = 1; + st.push(v); + } + } + } + return visited[to] != 0; +} + +static bool isBridge(const std::vector>>& g, int a, int b, int w) { + return !reachableWithoutEdge(g, a, b, a, b, w); +} + +int Graph::checkEuler(bool& circleExist) const { + circleExist = false; + if (directed) return 0; + if (n == 0) return 0; + + auto g = toAdjList(); + std::vector deg(n + 1, 0); + DSU dsu(n); + for (int u = 1; u <= n; ++u) + for (auto& e : g[u]) { + ++deg[u]; + dsu.unite(u, e.first); + } + + int start = 0; + for (int u = 1; u <= n; ++u) + if (deg[u] > 0) { + start = u; + break; + } + if (start == 0) { // no edges: the empty graph admits an Euler circuit + circleExist = true; + return 1; + } + for (int u = 1; u <= n; ++u) + if (deg[u] > 0 && dsu.find(u) != dsu.find(start)) return 0; + + int odd = 0, oddV = 0; + for (int u = 1; u <= n; ++u) + if (deg[u] % 2) { + ++odd; + oddV = u; + } + if (odd == 0) { + circleExist = true; + return start; + } + if (odd == 2) return oddV; + return 0; +} + +std::vector Graph::getEuleranTourFleri() const { + std::vector tour; + bool circleExist = false; + int start = checkEuler(circleExist); + if (start == 0) return tour; + + auto g = toAdjList(); + int total = 0; + for (int u = 1; u <= n; ++u) total += (int)g[u].size(); + total /= 2; + + int cur = start; + tour.push_back(cur); + for (int step = 0; step < total; ++step) { + int next = -1, nextW = 0; + for (auto& e : g[cur]) { + if (!isBridge(g, cur, e.first, e.second)) { + next = e.first; + nextW = e.second; + break; + } + if (next == -1) { // remember a bridge as fallback only + next = e.first; + nextW = e.second; + } + } + if (next == -1) { + tour.clear(); + return tour; + } + g[cur].erase({next, nextW}); + g[next].erase({cur, nextW}); + cur = next; + tour.push_back(cur); + } + return tour; +} + +std::vector Graph::getEuleranTourEffective() const { + std::vector tour; + bool circleExist = false; + int start = checkEuler(circleExist); + if (start == 0) return tour; + + auto g = toAdjList(); + long long total = 0; + for (int u = 1; u <= n; ++u) total += (long long)g[u].size(); + total /= 2; + + std::vector order; + std::stack st; + st.push(start); + long long used = 0; + while (!st.empty()) { + int u = st.top(); + if (g[u].empty()) { + order.push_back(u); + st.pop(); + } else { + auto it = g[u].begin(); + int v = it->first, w = it->second; + g[u].erase(it); + auto jt = g[v].lower_bound({u, INT_MIN}); + if (jt != g[v].end() && jt->first == u && jt->second == w) g[v].erase(jt); + st.push(v); + ++used; + } + } + + if (used != total) return std::vector(); + std::reverse(order.begin(), order.end()); + return order; +} diff --git a/Graph_Flow.cpp b/Graph_Flow.cpp new file mode 100644 index 0000000..1f99391 --- /dev/null +++ b/Graph_Flow.cpp @@ -0,0 +1,123 @@ +#include "Graph.h" +#include +#include +#include +#include +#include + +namespace { + +struct FlowEdge { + int to; + long long cap; + int rev; +}; + +using Residual = std::vector>; + +void addArc(Residual& g, int u, int v, long long cap) { + FlowEdge a{v, cap, (int)g[v].size()}; + FlowEdge b{u, 0, (int)g[u].size()}; + g[u].push_back(a); + g[v].push_back(b); +} + +Residual buildResidual(int n, const std::vector>& arcs) { + Residual g(n + 1); + for (auto& e : arcs) addArc(g, std::get<0>(e), std::get<1>(e), std::get<2>(e)); + return g; +} + +// Collapse parallel arcs by summing residual capacities so the result stays a simple graph. +Graph makeResidualGraph(int n, const Residual& g) { + std::map, long long> cap; + for (int u = 1; u <= n; ++u) + for (auto& e : g[u]) + if (e.cap > 0) cap[{u, e.to}] += e.cap; + + Graph res(n, true, true, 'E'); + for (auto& pr : cap) + res.addEdge(pr.first.first, pr.first.second, (int)pr.second); + return res; +} + +} // namespace + +Graph Graph::flowFordFulkerson(int source, int sink) const { + Residual g = buildResidual(n, toEdgeList()); + std::vector parent(n + 1), parentEdge(n + 1); + + while (true) { + std::fill(parent.begin(), parent.end(), -1); + parent[source] = source; + std::queue q; + q.push(source); + while (!q.empty()) { + int u = q.front(); + q.pop(); + for (int i = 0; i < (int)g[u].size(); ++i) { + const FlowEdge& e = g[u][i]; + if (e.cap > 0 && parent[e.to] == -1) { + parent[e.to] = u; + parentEdge[e.to] = i; + q.push(e.to); + } + } + } + if (parent[sink] == -1) break; + + long long bottleneck = std::numeric_limits::max(); + for (int v = sink; v != source; v = parent[v]) + bottleneck = std::min(bottleneck, g[parent[v]][parentEdge[v]].cap); + for (int v = sink; v != source; v = parent[v]) { + FlowEdge& e = g[parent[v]][parentEdge[v]]; + e.cap -= bottleneck; + g[v][e.rev].cap += bottleneck; + } + } + return makeResidualGraph(n, g); +} + +Graph Graph::flowDinitz(int source, int sink) const { + Residual g = buildResidual(n, toEdgeList()); + std::vector level(n + 1), ptr(n + 1); + + auto bfs = [&]() -> bool { + std::fill(level.begin(), level.end(), -1); + level[source] = 0; + std::queue q; + q.push(source); + while (!q.empty()) { + int u = q.front(); + q.pop(); + for (auto& e : g[u]) + if (e.cap > 0 && level[e.to] == -1) { + level[e.to] = level[u] + 1; + q.push(e.to); + } + } + return level[sink] != -1; + }; + + std::function dfs = [&](int u, long long pushed) -> long long { + if (pushed == 0) return 0; + if (u == sink) return pushed; + for (int& i = ptr[u]; i < (int)g[u].size(); ++i) { + FlowEdge& e = g[u][i]; + if (level[e.to] != level[u] + 1 || e.cap <= 0) continue; + long long pushedFlow = dfs(e.to, std::min(pushed, e.cap)); + if (pushedFlow == 0) continue; + e.cap -= pushedFlow; + g[e.to][e.rev].cap += pushedFlow; + return pushedFlow; + } + return 0; + }; + + while (bfs()) { + std::fill(ptr.begin(), ptr.end(), 0); + while (dfs(source, std::numeric_limits::max()) > 0) { + } + } + return makeResidualGraph(n, g); +} diff --git a/Graph_IO.cpp b/Graph_IO.cpp new file mode 100644 index 0000000..90e41b6 --- /dev/null +++ b/Graph_IO.cpp @@ -0,0 +1,321 @@ +#include "Graph.h" +#include +#include +#include +#include + +Graph::Graph() : n(0), directed(false), weighted(false), form('C') { + matrix.assign(1, std::vector(1, 0)); +} + +Graph::Graph(int n_) : n(n_), directed(false), weighted(true), form('L') { + adj.assign(n + 1, std::set>()); +} + +Graph::Graph(int n_, bool directed_, bool weighted_, char form_) + : n(n_), directed(directed_), weighted(weighted_), form(form_) { + if (form == 'C') matrix.assign(n + 1, std::vector(n + 1, 0)); + else if (form == 'L') adj.assign(n + 1, std::set>()); +} + +void Graph::readGraph(std::string fileName) { + std::ifstream in(fileName); + if (!in.is_open()) return; + + char t; + in >> t; + form = t; + + int m = 0; + if (form == 'E') in >> n >> m; + else in >> n; + + int d, w; + in >> d >> w; + directed = (d == 1); + weighted = (w == 1); + + matrix.clear(); + adj.clear(); + edges.clear(); + + if (form == 'C') { + matrix.assign(n + 1, std::vector(n + 1, 0)); + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= n; ++j) in >> matrix[i][j]; + if (!directed) { + for (int i = 1; i <= n; ++i) + for (int j = i + 1; j <= n; ++j) { + if (matrix[i][j] == 0) matrix[i][j] = matrix[j][i]; + if (matrix[j][i] == 0) matrix[j][i] = matrix[i][j]; + } + } + } else if (form == 'L') { + adj.assign(n + 1, std::set>()); + std::string line; + std::getline(in, line); // rest of the "D W" line + for (int i = 1; i <= n; ++i) { + std::getline(in, line); + std::istringstream ss(line); + if (weighted) { + int v, wgt; + while (ss >> v >> wgt) adj[i].insert({v, wgt}); + } else { + int v; + while (ss >> v) adj[i].insert({v, 1}); + } + } + if (!directed) { + for (int u = 1; u <= n; ++u) { + std::vector> snapshot(adj[u].begin(), adj[u].end()); + for (auto& pr : snapshot) adj[pr.first].insert({u, pr.second}); + } + } + } else { // 'E' + edges.reserve(m); + std::set> seen; + for (int i = 0; i < m; ++i) { + int a, b, wgt = 1; + in >> a >> b; + if (weighted) in >> wgt; + if (!directed) { + auto key = std::minmax(a, b); + if (!seen.insert({key.first, key.second}).second) continue; + } + edges.push_back({a, b, wgt}); + } + } +} + +void Graph::writeGraph(std::string fileName) { + std::ofstream out(fileName); + if (!out.is_open()) return; + + if (form == 'E') out << "E " << n << ' ' << edges.size() << '\n'; + else out << form << ' ' << n << '\n'; + out << (directed ? 1 : 0) << ' ' << (weighted ? 1 : 0) << '\n'; + + if (form == 'C') { + for (int i = 1; i <= n; ++i) { + for (int j = 1; j <= n; ++j) out << matrix[i][j] << ' '; + out << '\n'; + } + } else if (form == 'L') { + for (int i = 1; i <= n; ++i) { + bool first = true; + for (auto& e : adj[i]) { + if (!first) out << ' '; + first = false; + out << e.first; + if (weighted) out << ' ' << e.second; + } + out << '\n'; + } + } else { + for (auto& e : edges) { + out << std::get<0>(e) << ' ' << std::get<1>(e); + if (weighted) out << ' ' << std::get<2>(e); + out << '\n'; + } + } + out << '\n'; +} + +bool Graph::hasEdge(int from, int to) const { + if (from < 1 || from > n || to < 1 || to > n) return false; + if (form == 'C') return matrix[from][to] != 0; + if (form == 'L') { + auto it = adj[from].lower_bound({to, INT_MIN}); + return it != adj[from].end() && it->first == to; + } + for (auto& e : edges) + if ((std::get<0>(e) == from && std::get<1>(e) == to) || + (!directed && std::get<0>(e) == to && std::get<1>(e) == from)) + return true; + return false; +} + +int Graph::weightOf(int from, int to) const { + if (from < 1 || from > n || to < 1 || to > n) return 0; + if (form == 'C') return matrix[from][to]; + if (form == 'L') { + auto it = adj[from].lower_bound({to, INT_MIN}); + if (it != adj[from].end() && it->first == to) return it->second; + return 0; + } + for (auto& e : edges) + if ((std::get<0>(e) == from && std::get<1>(e) == to) || + (!directed && std::get<0>(e) == to && std::get<1>(e) == from)) + return std::get<2>(e); + return 0; +} + +void Graph::addEdge(int from, int to, int weight) { + if (!weighted) weight = 1; + if (hasEdge(from, to)) return; + if (form == 'C') { + matrix[from][to] = weight; + if (!directed) matrix[to][from] = weight; + } else if (form == 'L') { + adj[from].insert({to, weight}); + if (!directed) adj[to].insert({from, weight}); + } else { + edges.push_back({from, to, weight}); + } +} + +void Graph::removeEdge(int from, int to) { + if (form == 'C') { + if (matrix[from][to] == 0) return; + matrix[from][to] = 0; + if (!directed) matrix[to][from] = 0; + } else if (form == 'L') { + auto it = adj[from].lower_bound({to, INT_MIN}); + if (it != adj[from].end() && it->first == to) adj[from].erase(it); + if (!directed) { + auto jt = adj[to].lower_bound({from, INT_MIN}); + if (jt != adj[to].end() && jt->first == from) adj[to].erase(jt); + } + } else { + for (auto it = edges.begin(); it != edges.end(); ++it) { + bool match = (std::get<0>(*it) == from && std::get<1>(*it) == to) || + (!directed && std::get<0>(*it) == to && std::get<1>(*it) == from); + if (match) { + edges.erase(it); + break; + } + } + } +} + +int Graph::changeEdge(int from, int to, int newWeight) { + if (!weighted) newWeight = 1; + if (form == 'C') { + int old = matrix[from][to]; + if (old == 0) return 0; + matrix[from][to] = newWeight; + if (!directed) matrix[to][from] = newWeight; + return old; + } + if (form == 'L') { + auto it = adj[from].lower_bound({to, INT_MIN}); + if (it == adj[from].end() || it->first != to) return 0; + int old = it->second; + adj[from].erase(it); + adj[from].insert({to, newWeight}); + if (!directed) { + auto jt = adj[to].lower_bound({from, INT_MIN}); + if (jt != adj[to].end() && jt->first == from) { + adj[to].erase(jt); + adj[to].insert({from, newWeight}); + } + } + return old; + } + for (auto& e : edges) { + bool match = (std::get<0>(e) == from && std::get<1>(e) == to) || + (!directed && std::get<0>(e) == to && std::get<1>(e) == from); + if (match) { + int old = std::get<2>(e); + std::get<2>(e) = newWeight; + return old; + } + } + return 0; +} + +std::vector>> Graph::toAdjList() const { + if (form == 'L') return adj; + + std::vector>> g(n + 1); + if (form == 'C') { + for (int i = 1; i <= n; ++i) + for (int j = 1; j <= n; ++j) { + if (i == j || matrix[i][j] == 0) continue; + g[i].insert({j, matrix[i][j]}); + if (!directed) g[j].insert({i, matrix[i][j]}); + } + } else { + for (auto& e : edges) { + int a = std::get<0>(e), b = std::get<1>(e), w = std::get<2>(e); + g[a].insert({b, w}); + if (!directed) g[b].insert({a, w}); + } + } + return g; +} + +std::vector> Graph::toMatrix() const { + if (form == 'C') return matrix; + + std::vector> M(n + 1, std::vector(n + 1, 0)); + if (form == 'L') { + for (int u = 1; u <= n; ++u) + for (auto& e : adj[u]) { + M[u][e.first] = e.second; + if (!directed) M[e.first][u] = e.second; + } + } else { + for (auto& e : edges) { + int a = std::get<0>(e), b = std::get<1>(e), w = std::get<2>(e); + M[a][b] = w; + if (!directed) M[b][a] = w; + } + } + return M; +} + +std::vector> Graph::toEdgeList() const { + if (form == 'E') return edges; + + std::vector> el; + if (form == 'L') { + for (int u = 1; u <= n; ++u) + for (auto& e : adj[u]) { + if (!directed && e.first < u) continue; + el.push_back({u, e.first, e.second}); + } + } else { + for (int i = 1; i <= n; ++i) + for (int j = (directed ? 1 : i); j <= n; ++j) { + if (matrix[i][j] == 0) continue; + el.push_back({i, j, matrix[i][j]}); + } + } + return el; +} + +std::vector> Graph::toSimpleAdj() const { + auto g = toAdjList(); + std::vector> nb(n + 1); + for (int u = 1; u <= n; ++u) + for (auto& e : g[u]) { + nb[u].insert(e.first); + nb[e.first].insert(u); + } + return nb; +} + +void Graph::transformToAdjList() { + if (form == 'L') return; + adj = toAdjList(); + matrix.clear(); + edges.clear(); + form = 'L'; +} + +void Graph::transformToAdjMatrix() { + if (form == 'C') return; + matrix = toMatrix(); + adj.clear(); + edges.clear(); + form = 'C'; +} + +void Graph::transformToListOfEdges() { + if (form == 'E') return; + edges = toEdgeList(); + matrix.clear(); + adj.clear(); + form = 'E'; +} diff --git a/Graph_MST.cpp b/Graph_MST.cpp new file mode 100644 index 0000000..37a6e41 --- /dev/null +++ b/Graph_MST.cpp @@ -0,0 +1,86 @@ +#include "Graph.h" +#include "DSU.h" +#include +#include +#include +#include + +Graph Graph::getSpaingTreePrima() const { + Graph mst(n, false, true, 'L'); + auto g = toAdjList(); + + const long long INF = std::numeric_limits::max(); + std::vector minEdge(n + 1, INF); + std::vector parent(n + 1, 0); + std::vector used(n + 1, 0); + using Node = std::pair; + std::priority_queue, std::greater> pq; + + for (int s = 1; s <= n; ++s) { + if (used[s]) continue; + minEdge[s] = 0; + pq.push({0, s}); + while (!pq.empty()) { + auto [w, u] = pq.top(); + pq.pop(); + if (used[u]) continue; + used[u] = 1; + if (parent[u] != 0) mst.addEdge(u, parent[u], (int)w); + for (auto& e : g[u]) { + int v = e.first, wgt = e.second; + if (!used[v] && wgt < minEdge[v]) { + minEdge[v] = wgt; + parent[v] = u; + pq.push({wgt, v}); + } + } + } + } + return mst; +} + +Graph Graph::getSpaingTreeKruscal() const { + Graph mst(n, false, true, 'L'); + DSU dsu(n); + + auto el = toEdgeList(); + std::sort(el.begin(), el.end(), [](const auto& a, const auto& b) { + return std::get<2>(a) < std::get<2>(b); + }); + for (auto& e : el) { + int a = std::get<0>(e), b = std::get<1>(e), w = std::get<2>(e); + if (dsu.unite(a, b)) mst.addEdge(a, b, w); + } + return mst; +} + +Graph Graph::getSpaingTreeBoruvka() const { + Graph mst(n, false, true, 'L'); + DSU dsu(n); + + auto el = toEdgeList(); + int comp = n; + while (comp > 1) { + std::vector best(n + 1, -1); + for (int i = 0; i < (int)el.size(); ++i) { + int ra = dsu.find(std::get<0>(el[i])); + int rb = dsu.find(std::get<1>(el[i])); + if (ra == rb) continue; + int w = std::get<2>(el[i]); + if (best[ra] == -1 || w < std::get<2>(el[best[ra]])) best[ra] = i; + if (best[rb] == -1 || w < std::get<2>(el[best[rb]])) best[rb] = i; + } + bool merged = false; + for (int v = 1; v <= n; ++v) { + if (best[v] == -1) continue; + auto& e = el[best[v]]; + if (dsu.unite(std::get<0>(e), std::get<1>(e))) { + mst.addEdge(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + --comp; + merged = true; + } + } + if (!merged) break; + } + return mst; +} diff --git a/Graph_Matching.cpp b/Graph_Matching.cpp new file mode 100644 index 0000000..238e176 --- /dev/null +++ b/Graph_Matching.cpp @@ -0,0 +1,61 @@ +#include "Graph.h" +#include +#include +#include + +int Graph::checkBipart(std::vector& marks) const { + marks.assign(n + 1, 0); + auto nb = toSimpleAdj(); + + std::queue q; + for (int s = 1; s <= n; ++s) { + if (marks[s]) continue; + marks[s] = 'A'; + q.push(s); + while (!q.empty()) { + int u = q.front(); + q.pop(); + char opposite = (marks[u] == 'A') ? 'B' : 'A'; + for (int v : nb[u]) { + if (marks[v] == 0) { + marks[v] = opposite; + q.push(v); + } else if (marks[v] == marks[u]) { + return 0; + } + } + } + } + return 1; +} + +std::vector> Graph::getMaximumMatchingBipart() const { + std::vector> matching; + std::vector marks; + if (!checkBipart(marks)) return matching; + + auto nb = toSimpleAdj(); + std::vector match(n + 1, 0); // right vertex -> matched left vertex + std::vector used(n + 1, 0); + + std::function augment = [&](int u) -> bool { + used[u] = 1; + for (int v : nb[u]) { + if (marks[v] != 'B') continue; + if (match[v] == 0 || (!used[match[v]] && augment(match[v]))) { + match[v] = u; + return true; + } + } + return false; + }; + + for (int u = 1; u <= n; ++u) { + if (marks[u] != 'A') continue; + std::fill(used.begin(), used.end(), (char)0); + augment(u); + } + for (int v = 1; v <= n; ++v) + if (match[v] != 0) matching.push_back({match[v], v}); + return matching; +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a4c3c4c --- /dev/null +++ b/main.cpp @@ -0,0 +1,24 @@ +#include "Graph.h" +#include + +int main(int argc, char* argv[]) { + if (argc < 3) return 0; + + Graph g; + g.readGraph(argv[1]); + if (g.size() == 0) return 0; + + if (!g.isDirected() && g.isWeighted()) { + g.getSpaingTreeKruscal().writeGraph(argv[2]); + } else if (g.isDirected() && g.isWeighted()) { + g.flowDinitz(1, g.size()).writeGraph(argv[2]); + } else { + bool circleExist = false; + int start = g.checkEuler(circleExist); + if (start != 0) { + for (int v : g.getEuleranTourEffective()) std::cout << v << ' '; + std::cout << '\n'; + } + } + return 0; +}