/** Roman Kolganov, March 2019 */ #include using namespace std; const int N = 250; vector g[N]; int mate[N]; int state[N]; int p[N]; int dsu_rank[N]; int repr[N]; int tree_prev[N]; int edge_from[N]; int edge_to[N]; int left_mark[N]; int right_mark[N]; int current_mark = 0; int get(int v) { return p[v] == v ? v : (p[v] = get(p[v])); } void join(int u, int v) { u = get(u); v = get(v); if (dsu_rank[v] < dsu_rank[u]) { swap(u, v); } p[u] = v; if (dsu_rank[v] == dsu_rank[u]) { ++dsu_rank[v]; } } void promote(int v) { repr[get(v)] = v; } int base(int v) { return repr[get(v)]; } void get_path(int from, int to, list& path, bool rev) { if (from == to || (state[from] == 0 && mate[from] == 0)) { path.push_front(from); return; } if (state[from] == 0) { if (rev) { path.push_front(from); path.push_front(mate[from]); get_path(tree_prev[mate[from]], to, path, rev); } else { get_path(tree_prev[mate[from]], to, path, rev); path.push_front(mate[from]); path.push_front(from); } return; } if (rev) { path.push_front(from); get_path(edge_from[from], mate[from], path, !rev); get_path(edge_to[from], to, path, rev); } else { get_path(edge_to[from], to, path, rev); get_path(edge_from[from], mate[from], path, !rev); path.push_front(from); } } void augment(auto& path) { while (!path.empty()) { int x = path.front(); path.pop_front(); int y = path.front(); path.pop_front(); mate[x] = y; mate[y] = x; } } void shrink(vector& cycle, int v, int b, int from, int to) { for (int w = base(v); w != b; w = base(tree_prev[mate[w]])) { join(b, w); join(b, mate[w]); promote(b); edge_from[mate[w]] = from; edge_to[mate[w]] = to; cycle.push_back(mate[w]); } } bool dfs(int v) { for (int u : g[v]) { if (base(u) == base(v) || state[base(u)] == 1) { continue; } if (state[u] == -1) { if (mate[u] != 0) { state[u] = 1; tree_prev[u] = v; state[mate[u]] = 0; if (dfs(mate[u])) { return true; } } else { list path; get_path(v, 0, path, false); path.push_front(u); augment(path); return true; } } else { vector cycle; int cv = base(v); int cu = base(u); ++current_mark; left_mark[cu] = current_mark; right_mark[cv] = current_mark; while (left_mark[cv] != current_mark && right_mark[cu] != current_mark) { if (mate[cu] != 0) { cu = base(tree_prev[mate[cu]]); left_mark[cu] = current_mark; } if (mate[cv] != 0) { cv = base(tree_prev[mate[cv]]); right_mark[cv] = current_mark; } } int b = left_mark[cv] == current_mark ? cv : cu; shrink(cycle, v, b, v, u); shrink(cycle, u, b, u, v); for (int w : cycle) { if (dfs(w)) { return true; } } } } return false; } int main() { //freopen("schedule.in", "r", stdin); //freopen("schedule.out", "w", stdout); ios_base::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; int x, y; while (cin >> x >> y) { g[x].push_back(y); g[y].push_back(x); } for (int v = 1; v <= n; ++v) { if (mate[v] != 0) { continue; } fill_n(state + 1, n, -1); fill_n(dsu_rank + 1, n, 0); iota(p + 1, p + n + 1, 1); iota(repr + 1, repr + n + 1, 1); state[v] = 0; dfs(v); } vector> matching; for (int v = 1; v <= n; ++v) { if (mate[v] != 0) { matching.emplace_back(v, mate[v]); mate[mate[v]] = 0; } } cout << matching.size() * 2 << '\n'; for (auto [v, u] : matching) { cout << v << ' ' << u << '\n'; } }