Hướng dẫn giải của Hai Bộ Bài
Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
#include <bits/stdc++.h> #include <algorithm> #include <cassert> #include <limits> #include <queue> #include <vector> #include <vector> namespace atcoder { namespace internal { template <class T> struct simple_queue { std::vector<T> payload; int pos = 0; void reserve(int n) { payload.reserve(n); } int size() const { return int(payload.size()) - pos; } bool empty() const { return pos == int(payload.size()); } void push(const T& t) { payload.push_back(t); } T& front() { return payload[pos]; } void clear() { payload.clear(); pos = 0; } void pop() { pos++; } }; } // namespace internal } // namespace atcoder namespace atcoder { template <class Cap> struct mf_graph { public: mf_graph() : _n(0) {} explicit mf_graph(int n) : _n(n), g(n) {} int add_edge(int from, int to, Cap cap) { assert(0 <= from && from < _n); assert(0 <= to && to < _n); assert(0 <= cap); int m = int(pos.size()); pos.push_back({from, int(g[from].size())}); int from_id = int(g[from].size()); int to_id = int(g[to].size()); if (from == to) to_id++; g[from].push_back(_edge{to, to_id, cap}); g[to].push_back(_edge{from, from_id, 0}); return m; } struct edge { int from, to; Cap cap, flow; }; edge get_edge(int i) { int m = int(pos.size()); assert(0 <= i && i < m); auto _e = g[pos[i].first][pos[i].second]; auto _re = g[_e.to][_e.rev]; return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap}; } std::vector<edge> edges() { int m = int(pos.size()); std::vector<edge> result; for (int i = 0; i < m; i++) { result.push_back(get_edge(i)); } return result; } void change_edge(int i, Cap new_cap, Cap new_flow) { int m = int(pos.size()); assert(0 <= i && i < m); assert(0 <= new_flow && new_flow <= new_cap); auto& _e = g[pos[i].first][pos[i].second]; auto& _re = g[_e.to][_e.rev]; _e.cap = new_cap - new_flow; _re.cap = new_flow; } Cap flow(int s, int t) { return flow(s, t, std::numeric_limits<Cap>::max()); } Cap flow(int s, int t, Cap flow_limit) { assert(0 <= s && s < _n); assert(0 <= t && t < _n); assert(s != t); std::vector<int> level(_n), iter(_n); internal::simple_queue<int> que; auto bfs = [&]() { std::fill(level.begin(), level.end(), -1); level[s] = 0; que.clear(); que.push(s); while (!que.empty()) { int v = que.front(); que.pop(); for (auto e : g[v]) { if (e.cap == 0 || level[e.to] >= 0) continue; level[e.to] = level[v] + 1; if (e.to == t) return; que.push(e.to); } } }; auto dfs = [&](auto self, int v, Cap up) { if (v == s) return up; Cap res = 0; int level_v = level[v]; for (int& i = iter[v]; i < int(g[v].size()); i++) { _edge& e = g[v][i]; if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue; Cap d = self(self, e.to, std::min(up - res, g[e.to][e.rev].cap)); if (d <= 0) continue; g[v][i].cap += d; g[e.to][e.rev].cap -= d; res += d; if (res == up) return res; } level[v] = _n; return res; }; Cap flow = 0; while (flow < flow_limit) { bfs(); if (level[t] == -1) break; std::fill(iter.begin(), iter.end(), 0); Cap f = dfs(dfs, t, flow_limit - flow); if (!f) break; flow += f; } return flow; } std::vector<bool> min_cut(int s) { std::vector<bool> visited(_n); internal::simple_queue<int> que; que.push(s); while (!que.empty()) { int p = que.front(); que.pop(); visited[p] = true; for (auto e : g[p]) { if (e.cap && !visited[e.to]) { visited[e.to] = true; que.push(e.to); } } } return visited; } private: int _n; struct _edge { int to, rev; Cap cap; }; std::vector<std::pair<int, int>> pos; std::vector<std::vector<_edge>> g; }; } // namespace atcoder using namespace std; using namespace atcoder; struct dsu { vector<int> par, fre; dsu(int n) : par(n, -1), fre(n, 1) {} int trace(int u) { return par[u] < 0 ? u : par[u] = trace(par[u]); } int connect(int u, int v) { if ((u = trace(u)) == (v = trace(v))) { return u; } if (par[u] > par[v]) { swap(par[u], par[v]); } par[u] += par[v]; par[v] = u; fre[u] += fre[v]; return u; } int& operator[](int u) { return fre[u]; } }; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, m; cin >> n >> m; vector<pair<int, int>> a(n), b(m); for (int i = 0; i < n; i++) { cin >> a[i].first >> a[i].second; a[i].first--; a[i].second--; } for (int i = 0; i < m; i++) { cin >> b[i].first >> b[i].second; b[i].first--; b[i].second--; } int value_set = 2 * (n + m); auto gen_con_components = [&](vector<pair<int, int>>& a, vector<int>& com) { dsu dsu(value_set); for (auto [u, v] : a) { int p = dsu.connect(u, v); dsu[p]--; } for (int i = 0; i < value_set; i++) { int p = dsu.trace(i); if (dsu[p] < 0) { return false; } else if (dsu[p] > 0) { com[i] = p; } } return true; }; vector<int> com_a(value_set, -1), com_b(value_set, -1); if (!gen_con_components(a, com_a) || !gen_con_components(b, com_b)) { cout << "-1\n"; continue; } mf_graph<int> remove_values(2 * value_set + 2); vector<int> rep_edg(value_set, -1); auto left_side = [&](int u) { return u + 2; }; auto right_side = [&](int u) { return u + value_set + 2; }; int src = 0, snk = 1; for (int i = 0; i < value_set; i++) { remove_values.add_edge(src, left_side(i), 1); remove_values.add_edge(right_side(i), snk, 1); if (com_a[i] != -1 && com_b[i] != -1) { rep_edg[i] = remove_values.add_edge(left_side(com_a[i]), right_side(com_b[i]), 1); } } cout << value_set - remove_values.flow(src, snk) << '\n'; vector<bool> ok(value_set, true); for (int v = 0; v < value_set; v++) { if (rep_edg[v] != -1 && remove_values.get_edge(rep_edg[v]).flow == 1) { ok[v] = false; } } auto construct = [&](vector<pair<int, int>>& a) { int n = a.size(); vector<pair<int, int>> choice(n); mf_graph<int> mf(n + value_set + 2); int src = 0, snk = 1; auto card = [&](int i) { return 2 + i; }; auto value = [&](int v) { return 2 + n + v; }; for (int i = 0; i < n; i++) { auto [l, r] = a[i]; mf.add_edge(src, card(i), 1); int el = mf.add_edge(card(i), value(l), 1); int er = mf.add_edge(card(i), value(r), 1); choice[i] = {el, er}; } for (int v = 0; v < value_set; v++) { if (ok[v]) { mf.add_edge(value(v), snk, 1); } } assert(mf.flow(src, snk) == n); for (int i = 0; i < n; i++) { auto [l, r] = a[i]; auto [el, er] = choice[i]; int val = mf.get_edge(el).flow == 1 ? l : r; cout << val + 1 << " \n"[i + 1 == n]; } }; construct(a); construct(b); } }
Bình luận