## 1) Concise abridged problem statement

There are `n (2…100)` actors, each actor is either male or female (it is guaranteed the whole graph is bipartite, though the partition is not given).  
Juan approves some man–woman pairs (`m1` edges), Rosa approves some pairs (`m2` edges).

We want to choose the largest possible troupe (subset of actors) such that:

- Using **only Juan-approved pairs**, all chosen actors can be perfectly paired into marriages (a perfect matching on the chosen vertices).
- Using **only Rosa-approved pairs**, the same chosen actors can also be perfectly paired (another perfect matching).

Output:
- `k`: the maximum number of marriages (so troupe size is `2k`).
- Then output `k` Juan marriages and `k` Rosa marriages realizing this.

---

## 2) Detailed editorial (how the given solution works)

### Key reformulation

Let the actors be vertices of a bipartite graph with sides `A` and `B` (unknown initially).  
Juan provides edges `E1`, Rosa provides edges `E2`.

We need a maximum-size subset of vertices `S` such that:
- Graph `(S, E1)` has a perfect matching on `S`
- Graph `(S, E2)` has a perfect matching on `S`

Equivalently, we want to pick two perfect matchings (one in `E1`, one in `E2`) on the **same** vertex set, maximizing its size.

### Turn “two matchings on same vertices” into “disjoint directed cycles”

Assume we know the bipartition and orient edges:
- **Juan edges** are directed `A -> B`
- **Rosa edges** are directed `B -> A` (opposite direction)

Now consider selecting:
- some Juan edges (from `A` to `B`)
- some Rosa edges (from `B` to `A`)

with the constraint that each selected vertex has:
- exactly one selected outgoing edge (from that vertex’s side in the directed sense)
- exactly one selected incoming edge

If that holds, the selected directed edges form a vertex-disjoint union of directed cycles (each vertex has in-degree = out-degree = 1 within the chosen subgraph).

What does one such directed cycle represent?
- Along the cycle, Juan edges match `A` vertices to `B` vertices.
- Rosa edges match `B` vertices back to `A` vertices.
Thus, the set of vertices in the cycle is simultaneously perfectly matchable by Juan (take the Juan edges) and by Rosa (take the Rosa edges).

So the task becomes:

> Find a maximum-size collection of vertex-disjoint directed cycles in this directed graph, where edges are Juan-directed one way and Rosa-directed the opposite way.

Each cycle alternates Juan/Rosa edges, so the number of Juan edges selected equals the number of Rosa edges selected, and equals the number of marriages `k` contributed by those vertices.

### Enforcing vertex-disjointness via node splitting (capacity 1)

To ensure no vertex is used more than once across cycles, we do standard node-splitting:

For each actor `u` create:
- an “in” node `u`
- an “out” node `u+n`
- add an edge `u -> u+n` with capacity `1` and cost `0`

All directed “relationship edges” will go:
- from `out` of a vertex to `in` of another vertex

Thus, any flow that “passes through” a vertex must use `u -> u+n`, and capacity `1` limits usage to once.

### Convert to a min-cost circulation

We want to pick as many directed edges as possible in cycles.  
This is exactly a circulation problem: send flow around cycles.

Construction:
- For each actor `u`: edge `u -> u+n` capacity `1`, cost `0`.
- For each Juan or Rosa allowed pair, add a directed edge (capacity `1`) from `out` to `in` in the correct direction, with **cost = -1** (profit of selecting it).
- Then find a **minimum-cost circulation**. Since costs are negative on relationship edges, the algorithm will push flow along negative cycles to reduce total cost, i.e., to select as many profitable edges as possible, limited by vertex capacities.

Important: This graph can have **negative cycles**, so many “standard” min-cost flow implementations (that assume no negative cycles or rely on potentials from a shortest path tree) may fail. The provided code uses a **network simplex**-style algorithm for **minimum-cost circulation**, which can handle negative cycles.

### Why divide by 2 at the end?

Every valid directed cycle alternates:
- one Juan edge (cost -1)
- one Rosa edge (cost -1)
So each marriage “slot” corresponds to **two** selected directed edges total cost `-2`.

Let total minimum cost be `C` (negative). Then:
- number of selected directed relationship edges = `-C`
- number of marriages `k` = `(-C) / 2`

Hence:
```cpp
ans = -min_cost / 2;
```

### Recovering the actual marriages

During graph building, the solution records each added relationship edge with metadata:
- its edge id in the circulation graph
- original endpoints `(u, v)`
- whether it’s Juan (type 1) or Rosa (type 2)

After min-cost circulation, if that edge carries flow `> 0`, it was selected.
Collect:
- all selected Juan edges → print as Juan marriages
- all selected Rosa edges → print as Rosa marriages

They will form perfect matchings over the chosen troupe because the circulation guarantees each chosen vertex has one in and one out across the cycle cover.

---

## 3) Provided C++ solution with detailed line-by-line comments

```cpp
#include <bits/stdc++.h>
// #include <coding_library/graph/mincost_circulation.hpp>

using namespace std;

// Pretty-print a pair as "first second"
template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

// Read a pair from input
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

// Read a whole vector from input (assumes it is already sized)
template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

// Print a vector (space-separated)
template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

// Min-cost circulation solver using a (primal) network simplex style approach.
// Works even when the graph has negative cycles (which we need here).
template<typename T>
class MinCostCirculation {
  private:
    // Internal directed edge representation with residual pair (reverse edge).
    struct Edge {
        int from, to;      // endpoints
        T capacity, cost;  // capacity and per-unit cost
        T flow;            // current flow on this edge
        Edge(int _from, int _to, T _capacity, T _cost, T _flow = 0)
            : from(_from),
              to(_to),
              capacity(_capacity),
              cost(_cost),
              flow(_flow) {}
    };

    int n;                      // number of nodes
    vector<Edge> edges;         // all edges (forward+reverse)
    vector<int> pei, depth;     // parent edge index in the basis tree + depth
    vector<T> dual;             // node potentials (dual variables)
    vector<set<int>> tree;      // current spanning tree (basis), adjacency via edge indices

    // DFS to compute depths, parent edges, and dual potentials along the current tree.
    void dfs(int node) {
        for(auto ei: tree[node]) {
            if(ei == pei[node]) {
                continue; // skip going back to parent
            }
            int vec = edges[ei].to;              // child node
            dual[vec] = dual[node] + edges[ei].cost; // potential = parent + tree edge cost
            pei[vec] = (ei ^ 1);                 // store reverse edge index as "parent edge"
            depth[vec] = 1 + depth[node];        // depth in the tree
            dfs(vec);
        }
    }

    // Walk the unique path in the tree between edges[ei].from and edges[ei].to,
    // applying callback cb to each edge index on the fundamental cycle created by adding ei.
    template<typename CB>
    void walk(int ei, CB&& cb) {
        cb(ei); // include the entering edge itself
        int a = edges[ei].from, b = edges[ei].to;
        while(a != b) {
            // Move up the deeper node until both meet at LCA.
            if(depth[a] > depth[b]) {
                cb(pei[a] ^ 1);          // edge from parent->a
                a = edges[pei[a]].to;    // go to parent of a
            } else {
                cb(pei[b]);              // edge from b->parent (note pei[b] is reverse)
                b = edges[pei[b]].to;    // go to parent of b
            }
        }
    }

  public:
    MinCostCirculation(int _n = 0) { init(_n); }

    // Initialize internal structures for _n nodes.
    void init(int _n) {
        n = _n;
        edges.clear();
        pei.assign(n + 1, -1);
        depth.assign(n + 1, 0);
        dual.assign(n + 1, 0);
        tree.assign(n + 1, set<int>());
    }

    int size() const { return n; }

    // Add directed edge (from->to) and its reverse edge (to->from).
    // Returns the index id of the forward edge.
    int add_edge(int from, int to, T capacity, T cost) {
        int id = edges.size();
        edges.push_back(Edge(from, to, capacity, cost, 0));     // forward
        edges.push_back(Edge(to, from, 0, -cost, 0));           // reverse residual
        return id;
    }

    // Compute minimum-cost circulation. Returns minimal total cost.
    T min_circulation() {
        // Add an artificial root node indexed as n (note init sizes arrays as n+1).
        // Connect root to every node with 0 capacity edges to build an initial feasible basis tree.
        for(int i = 0; i < n; i++) {
            int ei = add_edge(n, i, 0, 0);     // edge root->i
            tree[n].insert(ei);                // put in basis tree
            tree[i].insert(ei ^ 1);            // and also store reverse for adjacency
        }

        T answer = 0;       // total cost
        T flow;             // augmentation flow
        int cost, ein, eout, ptr = 0;
        const int B = 3 * n; // batch size for scanning edges (heuristic)

        // Outer loop: repeatedly find a negative reduced-cost entering edge and pivot.
        for(int z = 0; z < (int)edges.size() / B + 1; z++) {
            if(!z) {
                dfs(n); // compute potentials (dual) from current basis tree
            }

            // Find entering edge with minimum reduced cost among a batch of edges.
            pair<T, int> pin = {0, -1}; // (best reduced cost, edge id). Starts at 0 => only negative improves.
            for(int t = 0; t < B; t++, (++ptr) %= (int)edges.size()) {
                auto& e = edges[ptr];
                if(e.flow < e.capacity) { // residual capacity exists
                    // reduced cost = dual[from] + cost - dual[to]
                    pin = min(pin, make_pair(dual[e.from] + e.cost - dual[e.to], ptr));
                }
            }

            tie(cost, ein) = pin;
            if(cost == 0) {
                continue; // no negative reduced-cost edge found in this batch
            }

            // Determine how much flow we can send along the fundamental cycle.
            // Start with entering edge residual.
            pair<T, int> pout = {edges[ein].capacity - edges[ein].flow, ein};

            // Along the cycle, find the bottleneck residual edge (leaving edge).
            walk(ein, [&](int ei) {
                pout = min(pout, make_pair(edges[ei].capacity - edges[ei].flow, ei));
            });

            tie(flow, eout) = pout;

            // Augment 'flow' units along the cycle.
            walk(ein, [&](int ei) {
                edges[ei].flow += flow;
                edges[ei ^ 1].flow -= flow; // maintain antisymmetry with reverse edge
            });

            // Pivot: add entering edge to basis tree, remove leaving edge from basis tree.
            tree[edges[ein].from].insert(ein);
            tree[edges[ein].to].insert(ein ^ 1);
            tree[edges[eout].from].erase(eout);
            tree[edges[eout].to].erase(eout ^ 1);

            // Update objective.
            answer += flow * cost;

            // Restart so that dfs recomputes potentials from scratch next iteration.
            z = -1;
        }
        return answer;
    }

    // Access stored edge by id (forward edge id).
    const Edge& get_edge(int id) const { return edges[id]; }
};

int n, m1, m2;
vector<vector<int>> G; // adjacency matrix storing bitmask: 1 if Juan edge, 2 if Rosa edge

// Read input and store edges in G
void read() {
    cin >> n >> m1 >> m2;
    G.assign(n, vector<int>(n, 0));
    for(int i = 0; i < m1; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        G[u][v] |= 1; // mark Juan approval
        G[v][u] |= 1;
    }
    for(int i = 0; i < m2; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        G[u][v] |= 2; // mark Rosa approval
        G[v][u] |= 2;
    }
}

void solve() {
    // Color the graph to recover the bipartition (guaranteed bipartite).
    vector<int> color(n, -1);

    // DFS bipartite check/coloring over edges existing in either set.
    function<bool(int, int)> check_bipartite_dfs = [&](int u, int c) -> bool {
        color[u] = c;
        for(int v = 0; v < n; v++) {
            if(!G[u][v]) continue; // no edge between u and v in either set
            if(color[v] == -1) {
                if(!check_bipartite_dfs(v, 1 - c)) return false;
            } else if(color[v] == color[u]) {
                return false; // conflict
            }
        }
        return true;
    };

    // Graph may be disconnected, so run DFS from each component.
    for(int i = 0; i < n; i++) {
        if(color[i] == -1) {
            assert(check_bipartite_dfs(i, 0)); // problem guarantees bipartite
        }
    }

    // Build circulation graph on 2*n nodes (node splitting).
    // Node u is "in", node u+n is "out".
    MinCostCirculation<int64_t> mcc(2 * n);

    // Store info to reconstruct chosen marriages later:
    // (edge_id_in_flow_graph, u, v, type(1=Juan,2=Rosa))
    vector<tuple<int, int, int, int>> edge_info;

    for(int i = 0; i < n; i++) {
        // Capacity 1 through each actor to enforce vertex-disjointness.
        mcc.add_edge(i, i + n, 1, 0);

        for(int j = i + 1; j < n; j++) {
            if(!G[i][j]) continue;

            // Add directed relationship edges with cost -1 (profit).
            // Orientation rule after coloring:
            // - Juan edges always A(color=0)->B(color=1)
            // - Rosa edges always B(color=1)->A(color=0)

            // If Juan approves this pair (bit 1 set)
            if(G[i][j] == 1 || G[i][j] == 3) {
                if(color[i] == 0 && color[j] == 1) {
                    // i(out) -> j(in)
                    int ei = mcc.add_edge(i + n, j, 1, -1);
                    edge_info.push_back({ei, i, j, 1});
                } else {
                    // j(out) -> i(in) (swap to keep A->B)
                    int ei = mcc.add_edge(j + n, i, 1, -1);
                    edge_info.push_back({ei, i, j, 1});
                }
            }

            // If Rosa approves this pair (bit 2 set)
            if(G[i][j] == 2 || G[i][j] == 3) {
                if(color[i] == 1 && color[j] == 0) {
                    // i is in B, j is in A, so i(out)->j(in) is B->A
                    int ei = mcc.add_edge(i + n, j, 1, -1);
                    edge_info.push_back({ei, i, j, 2});
                } else {
                    // otherwise swap
                    int ei = mcc.add_edge(j + n, i, 1, -1);
                    edge_info.push_back({ei, i, j, 2});
                }
            }
        }
    }

    // Minimum cost is negative; every marriage contributes cost -2 (one Juan + one Rosa edge).
    int ans = -mcc.min_circulation() / 2;

    // Recover which edges were selected (flow > 0).
    vector<pair<int, int>> juan, rosa;
    for(auto [ei, u, v, type]: edge_info) {
        if(mcc.get_edge(ei).flow > 0) {
            if(type == 1) juan.push_back({u, v});
            else          rosa.push_back({u, v});
        }
    }

    // Output
    cout << ans << '\n';
    for(auto [u, v]: juan) {
        cout << u + 1 << ' ' << v + 1 << '\n';
    }
    for(auto [u, v]: rosa) {
        cout << u + 1 << ' ' << v + 1 << '\n';
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        solve();
    }
    return 0;
}
```

---

## 4) Python solution (same idea, detailed comments)

Python note: implementing network simplex is long; instead, for `n ≤ 100` we can solve via **maximum bipartite matching in an auxiliary graph** using Dulmage–Mendelsohn style? Unfortunately the “two matchings on same vertex set” maximum common perfectly-matchable subset is not a plain matching problem.

So to stay faithful and correct, below is a Python implementation of **min-cost circulation with negative cycles** using a standard approach: **cycle-canceling** with Bellman–Ford to find negative cycles.  
This is slower in theory, but with `n ≤ 100` (so circulation graph has ≤ 200 nodes and O(n^2) edges) it is typically fine.

```python
import sys

# -------------- Min-Cost Circulation via Negative-Cycle Cancelling --------------

class Edge:
    __slots__ = ("to", "rev", "cap", "cost")
    def __init__(self, to, rev, cap, cost):
        self.to = to        # endpoint
        self.rev = rev      # index of reverse edge in g[to]
        self.cap = cap      # residual capacity
        self.cost = cost    # cost per unit flow

class MinCostCirculation:
    """
    Finds a minimum-cost circulation in a directed graph with capacities and costs.
    Works with negative cycles by repeatedly canceling them (Bellman-Ford).
    Graph size here is small enough for this approach.
    """
    def __init__(self, n):
        self.n = n
        self.g = [[] for _ in range(n)]

    def add_edge(self, fr, to, cap, cost):
        """
        Add edge fr->to and reverse edge to->fr.
        Returns (fr, index) to identify the forward edge later.
        """
        fwd = Edge(to, len(self.g[to]), cap, cost)
        rev = Edge(fr, len(self.g[fr]), 0, -cost)
        self.g[fr].append(fwd)
        self.g[to].append(rev)
        return fr, len(self.g[fr]) - 1

    def min_cost_circulation(self):
        """
        Cycle-canceling:
        - While there exists a negative cycle in the residual graph,
          send as much flow as possible around it.
        Returns total min cost.
        """
        n = self.n
        cost_total = 0

        while True:
            # Bellman-Ford to detect any negative cycle reachable from a super source.
            # We simulate super source by initializing dist=0 for all nodes.
            dist = [0] * n
            parent_v = [-1] * n      # parent vertex in relaxation
            parent_e = [-1] * n      # parent edge index in g[parent_v]

            x = -1
            for _ in range(n):
                x = -1
                for v in range(n):
                    dv = dist[v]
                    for ei, e in enumerate(self.g[v]):
                        if e.cap <= 0:
                            continue
                        nd = dv + e.cost
                        if nd < dist[e.to]:
                            dist[e.to] = nd
                            parent_v[e.to] = v
                            parent_e[e.to] = ei
                            x = e.to

            if x == -1:
                # No relaxation on nth iteration => no negative cycle
                break

            # 'x' is on or reaches a negative cycle; move x inside the cycle
            for _ in range(n):
                x = parent_v[x]

            # Reconstruct the cycle by walking parents until we return to x
            cycle = []
            cur = x
            while True:
                pv = parent_v[cur]
                pe = parent_e[cur]
                cycle.append((pv, pe))  # edge pv -> cur is pe in g[pv]
                cur = pv
                if cur == x:
                    break

            # Determine bottleneck capacity along the cycle
            add = 10**18
            for v, ei in cycle:
                e = self.g[v][ei]
                if e.cap < add:
                    add = e.cap

            # Augment flow along the cycle and update total cost
            for v, ei in cycle:
                e = self.g[v][ei]
                rev = self.g[e.to][e.rev]
                e.cap -= add
                rev.cap += add
                cost_total += add * e.cost

        return cost_total

# -------------- Problem Solution --------------

def solve():
    data = sys.stdin.read().strip().split()
    if not data:
        return
    it = iter(data)
    n = int(next(it))
    m1 = int(next(it))
    m2 = int(next(it))

    # G[u][v] bitmask: 1 for Juan, 2 for Rosa
    G = [[0] * n for _ in range(n)]
    for _ in range(m1):
        u = int(next(it)) - 1
        v = int(next(it)) - 1
        G[u][v] |= 1
        G[v][u] |= 1
    for _ in range(m2):
        u = int(next(it)) - 1
        v = int(next(it)) - 1
        G[u][v] |= 2
        G[v][u] |= 2

    # Bipartite coloring using all edges that exist in either set
    color = [-1] * n
    sys.setrecursionlimit(10000)

    def dfs(u, c):
        color[u] = c
        for v in range(n):
            if G[u][v] == 0:
                continue
            if color[v] == -1:
                if not dfs(v, 1 - c):
                    return False
            elif color[v] == color[u]:
                return False
        return True

    for i in range(n):
        if color[i] == -1:
            ok = dfs(i, 0)
            # guaranteed bipartite by the original problem setting
            if not ok:
                raise RuntimeError("Graph is not bipartite")

    # Build circulation graph on 2*n nodes:
    # node u = "in", node u+n = "out"
    N = 2 * n
    mcc = MinCostCirculation(N)

    # For reconstruction, store (fr, idx, u, v, typ)
    edge_info = []

    for u in range(n):
        # capacity 1 through each vertex
        mcc.add_edge(u, u + n, 1, 0)

    for i in range(n):
        for j in range(i + 1, n):
            if G[i][j] == 0:
                continue

            # Juan edge: A(0) -> B(1)
            if G[i][j] & 1:
                if color[i] == 0 and color[j] == 1:
                    fr, idx = mcc.add_edge(i + n, j, 1, -1)
                    edge_info.append((fr, idx, i, j, 1))
                else:
                    fr, idx = mcc.add_edge(j + n, i, 1, -1)
                    edge_info.append((fr, idx, i, j, 1))

            # Rosa edge: B(1) -> A(0)
            if G[i][j] & 2:
                if color[i] == 1 and color[j] == 0:
                    fr, idx = mcc.add_edge(i + n, j, 1, -1)
                    edge_info.append((fr, idx, i, j, 2))
                else:
                    fr, idx = mcc.add_edge(j + n, i, 1, -1)
                    edge_info.append((fr, idx, i, j, 2))

    min_cost = mcc.min_cost_circulation()
    k = (-min_cost) // 2  # each marriage corresponds to 2 selected edges

    juan = []
    rosa = []

    # An original edge is chosen if its residual cap is 0 (since initial cap was 1)
    for fr, idx, u, v, typ in edge_info:
        e = mcc.g[fr][idx]
        used = (e.cap == 0)
        if used:
            if typ == 1:
                juan.append((u, v))
            else:
                rosa.append((u, v))

    out = []
    out.append(str(k))
    for u, v in juan:
        out.append(f"{u+1} {v+1}")
    for u, v in rosa:
        out.append(f"{u+1} {v+1}")
    sys.stdout.write("\n".join(out))

if __name__ == "__main__":
    solve()
```

---

## 5) Compressed editorial

1. Color the union graph `(V, E1 ∪ E2)` to get bipartition `A/B` (guaranteed bipartite).  
2. Direct edges: Juan `A→B`, Rosa `B→A`.  
3. A subset of actors supports perfect matchings in both graphs iff we can choose a vertex-disjoint set of directed cycles that alternates Juan/Rosa edges.  
4. Enforce vertex-disjointness by splitting each vertex `u` into `u_in` and `u_out` with capacity-1 edge `u_in→u_out`. All relationship edges go `out→in`.  
5. Give each relationship edge cost `-1` (profit), capacity `1`. Then the best solution is a **minimum-cost circulation** (it will push flow along negative cycles to pick as many edges as possible).  
6. Total cost is `-2k` (each marriage contributes one Juan + one Rosa edge), so `k = -cost/2`.  
7. Output chosen Juan edges and chosen Rosa edges as the two matchings.