/* Problem URL: https://cses.fi/problemset/task/1696 */ #include #include #include using namespace std; using namespace __gnu_pbds; template > using ordered_set = tree; #define V vector #define rmin(a, b) a = min(a, b) #define rmax(a, b) a = max(a, b) #define rep(i, lim) for (int i = 0; i < (lim); i++) #define nrep(i, s, lim) for (int i = s; i < (lim); i++) #define repv(i, v) for (auto &i : (v)) #define fillv(v) for (auto &itr_ : (v)) { cin >> itr_; } #define sortv(v) sort(v.begin(), v.end()) #define all(v) (v).begin(), (v).end() using vi = vector; using vvi = vector; using vvvi = vector; using vvvvi = vector; using ll = long long; using vl = vector; using vvl = vector; using vvvl = vector; using vvvvl = vector; template auto operator<<(ostream &os, const vector &vec)->ostream& { os << vec[0]; for (size_t i = 1; i < vec.size(); i++) { os << ' ' << vec[i]; } os << '\n'; return os; } template auto operator>>(istream &is, vector &vec)->istream& { for (auto &i : vec) { is >> i; } return is; } template auto operator<<(ostream &os, const vector> &vec)->ostream& { for (auto &i : vec) { os << i[0]; for (size_t j = 1; j < i.size(); j++) { os << ' ' << i[j]; } os << '\n'; } return os; } template auto operator>>(istream &is, vector> &vec)->istream& { for (auto &i : vec) { for (auto &j : i) { is >> j; } } return is; } const int INF = INT32_MAX >> 1; struct dinitz { const bool scaling = false; // com scaling -> O(nm log(MAXCAP)), int lim; // com constante alta struct edge { int to, cap, rev, flow; bool res; edge(int to_, int cap_, int rev_, bool res_) : to(to_), cap(cap_), rev(rev_), flow(0), res(res_) {} }; vector> g; vector lev, beg; ll F; dinitz(int n) : g(n), F(0) {} void add(int a, int b, int c) { g[a].emplace_back(b, c, g[b].size(), false); g[b].emplace_back(a, 0, g[a].size()-1, true); } bool bfs(int s, int t) { lev = vector(g.size(), -1); lev[s] = 0; beg = vector(g.size(), 0); queue q; q.push(s); while (q.size()) { int u = q.front(); q.pop(); for (auto& i : g[u]) { if (lev[i.to] != -1 or (i.flow == i.cap)) continue; if (scaling and i.cap - i.flow < lim) continue; lev[i.to] = lev[u] + 1; q.push(i.to); } } return lev[t] != -1; } int dfs(int v, int s, int f = INF) { if (!f or v == s) return f; for (int& i = beg[v]; i < g[v].size(); i++) { auto& e = g[v][i]; if (lev[e.to] != lev[v] + 1) continue; int foi = dfs(e.to, s, min(f, e.cap - e.flow)); if (!foi) continue; e.flow += foi, g[e.to][e.rev].flow -= foi; return foi; } return 0; } ll max_flow(int s, int t) { for (lim = scaling ? (1<<30) : 1; lim; lim /= 2) while (bfs(s, t)) while (int ff = dfs(s, t)) F += ff; return F; } }; // Recupera as arestas do corte s-t vector> get_cut(dinitz& g, int s, int t) { g.max_flow(s, t); vector> cut; vector vis(g.g.size(), 0), st = {s}; vis[s] = 1; while (st.size()) { int u = st.back(); st.pop_back(); for (auto e : g.g[u]) if (!vis[e.to] and e.flow < e.cap) vis[e.to] = 1, st.push_back(e.to); } for (int i = 0; i < g.g.size(); i++) for (auto e : g.g[i]) if (vis[i] and !vis[e.to] and !e.res) cut.emplace_back(i, e.to); return cut; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, k; cin >> n >> m >> k; dinitz din(n + m + 2); int s = 0; int t = n + m + 1; rep(i, n) { din.add(s, i + 1, 1); } rep(i, m) { din.add(i + n + 1, t, 1); } while (k--) { int a, b; cin >> a >> b; b += n; din.add(a, b, 1); } int ans = din.max_flow(s, t); cout << ans << '\n'; rep(i, n) { ans = -1; for (auto edge : din.g[i + 1]) { if (edge.res || edge.flow == 0) { continue; } ans = edge.to - n; } if (ans == -1) { continue; } cout << i + 1 << ' ' << ans << '\n'; } }