<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

190. Dominoes
time limit per test: 0.25 sec.
memory limit per test: 4096 KB
input: standard input
output: standard output



There is a NxN squared chessboard (1<=N<=40). P squares were removed from the chessboard (0<=P<N*N). It is necessary to find out whether it is possible to cover the remaining part of the chessboard with dominoes dice (each die is 2x1 squares sized). Each die should lie on two neighboring squares exactly. No two dice can cover one and the same square. Your task is to find the covering, if it exists.

Input
The first line contains two integer numbers N and P separated by a space. Each of the following P lines contains a pair of numbers separated by a space - coordinates of the removed square (1<=Xi, Yi<=N). The bottom left square has the coordinates (1, 1), the bottom right square - (N, 1).

Output
If the covering exists, output "Yes" to the first line and "No" in the opposite case. If the first answer was positive, then output to the second line integer number Nh - the number of horizontally placed dice. Each of the following Nh lines should contain two integers - the coordinates of the left square covered by a corresponding die. Output to the next line Nv - the number of vertically placed dice. And the following Nv lines should contain the coordinates of the bottom square covered by a corresponding die.

Sample test(s)

Input
4 10
1 3
1 2
1 1
2 1
3 1
4 1
3 2
4 2
3 3
4 3

Output
Yes
2
1 4
3 4
1
2 2
Author:	Michael R. Mirzayanov
Resource:	ACM International Collegiate Programming Contest 2003-2004
North-Eastern European Region, Southern Subregion
Date:	2003 October, 9

<|response|>
1. Abridged problem statement  
We have an N×N grid (1 ≤ N ≤ 40). P cells are removed (0 ≤ P < N²). Determine whether the remaining cells can be exactly covered by non‐overlapping 2×1 dominoes placed on orthogonally adjacent cells. If a tiling exists, print “Yes”, then:  
  • Nh (number of horizontal dominoes), followed by Nh lines with the coordinates of each domino’s left cell.  
  • Nv (number of vertical dominoes), followed by Nv lines with the coordinates of each domino’s bottom cell.  
Otherwise print “No”.

2. Key observations needed to solve the problem  
  • On a checkerboard coloring, every domino covers one black and one white cell.  
  • A tiling of all free cells exists if and only if there is a perfect matching in the bipartite graph whose vertices are the free black and white cells, and edges connect orthogonally adjacent free cells.  
  • We can test for a perfect matching in O(E√V) using the Hopcroft–Karp algorithm, which is efficient for up to N=40 (V≤1600, E≤4V).

3. Full solution approach based on the observations  
  1. Read N and P, and mark the removed cells in a Boolean grid.  
  2. Count free cells = N·N − P. If this count is odd, immediately print “No” and exit.  
  3. Color each free cell black or white by parity of (x+y). Collect black cells into a list B and white cells into a list W, assigning each a unique index.  
  4. Build a bipartite graph: for each black cell at (x,y), check its 4 neighbors (up/down/left/right). If a neighbor is a free white cell, add an edge from the black‐index to the white‐index.  
  5. Run Hopcroft–Karp to find a maximum matching. Let M be the size of the matching. If 2·M ≠ (number of free cells), print “No”. Otherwise proceed.  
  6. Extract all matched pairs (b,w). For each pair, compare their coordinates:  
     – If they share the same x, it’s horizontal. Record the leftmost cell.  
     – Otherwise it’s vertical. Record the bottommost cell.  
  7. Print “Yes”, then Nh and the list of horizontal dominoes, followed by Nv and the list of vertical dominoes.

4. C++ implementation with detailed comments  
```cpp
#include <bits/stdc++.h>
using namespace std;

// Hopcroft-Karp for bipartite matching in O(E sqrt(V))
struct HopcroftKarp {
    int n, m;
    vector<vector<int>> adj;   // adj[u] = list of v's
    vector<int> dist, matchL, matchR;

    HopcroftKarp(int _n, int _m)
        : n(_n), m(_m),
          adj(_n),
          dist(_n),
          matchL(_n, -1),
          matchR(_m, -1) {}

    // Add edge from left node u to right node v
    void addEdge(int u, int v) {
        adj[u].push_back(v);
    }

    // BFS to build layers; returns true if there is an augmenting path
    bool bfs() {
        queue<int> q;
        // Initialize distances
        for (int u = 0; u < n; u++) {
            if (matchL[u] == -1) {
                dist[u] = 0;
                q.push(u);
            } else {
                dist[u] = -1;
            }
        }
        bool foundPath = false;
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int v : adj[u]) {
                int u2 = matchR[v];
                if (u2 == -1) {
                    // We found a free right node ⇒ augmenting path exists
                    foundPath = true;
                } else if (dist[u2] < 0) {
                    // Layer the paired left node
                    dist[u2] = dist[u] + 1;
                    q.push(u2);
                }
            }
        }
        return foundPath;
    }

    // DFS to find augmenting paths
    bool dfs(int u) {
        for (int v : adj[u]) {
            int u2 = matchR[v];
            if (u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))) {
                // Match u-v
                matchL[u] = v;
                matchR[v] = u;
                return true;
            }
        }
        // Mark u as dead end
        dist[u] = -1;
        return false;
    }

    // Compute maximum matching; returns number of matches
    int maxMatching() {
        int result = 0;
        while (bfs()) {
            for (int u = 0; u < n; u++) {
                if (matchL[u] == -1 && dfs(u)) {
                    result++;
                }
            }
        }
        return result;
    }
};

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

    int N, P;
    cin >> N >> P;
    vector<vector<bool>> freeCell(N+1, vector<bool>(N+1, true));
    for (int i = 0; i < P; i++) {
        int x, y;
        cin >> x >> y;
        freeCell[x][y] = false;
    }

    int totalFree = N*N - P;
    // If odd number of free cells, no perfect tiling
    if (totalFree % 2) {
        cout << "No\n";
        return 0;
    }

    // Partition free cells by checkerboard parity
    vector<pair<int,int>> blackCells, whiteCells;
    blackCells.reserve(totalFree/2);
    whiteCells.reserve(totalFree/2);
    // Maps from (x,y) → index in blackCells / whiteCells
    map<pair<int,int>,int> bIndex, wIndex;

    for (int x = 1; x <= N; x++) {
        for (int y = 1; y <= N; y++) {
            if (!freeCell[x][y]) continue;
            if (((x + y) & 1) == 0) {
                bIndex[{x,y}] = blackCells.size();
                blackCells.emplace_back(x,y);
            } else {
                wIndex[{x,y}] = whiteCells.size();
                whiteCells.emplace_back(x,y);
            }
        }
    }

    // Build bipartite graph
    HopcroftKarp hk((int)blackCells.size(), (int)whiteCells.size());
    int dx[4] = {1,-1,0,0}, dy[4] = {0,0,1,-1};
    for (int i = 0; i < (int)blackCells.size(); i++) {
        auto [x,y] = blackCells[i];
        for (int d = 0; d < 4; d++) {
            int nx = x + dx[d], ny = y + dy[d];
            if (nx < 1 || nx > N || ny < 1 || ny > N) continue;
            if (!freeCell[nx][ny]) continue;
            // If neighbor is white, add edge
            auto it = wIndex.find({nx,ny});
            if (it != wIndex.end()) {
                hk.addEdge(i, it->second);
            }
        }
    }

    // Find maximum matching
    int M = hk.maxMatching();
    if (2*M != totalFree) {
        cout << "No\n";
        return 0;
    }

    // We have a perfect tiling
    cout << "Yes\n";
    vector<pair<int,int>> horiz, vert;
    // Extract dominoes from matched pairs
    for (int bi = 0; bi < (int)blackCells.size(); bi++) {
        int wi = hk.matchL[bi];
        if (wi < 0) continue;
        auto [bx, by] = blackCells[bi];
        auto [wx, wy] = whiteCells[wi];
        if (bx == wx) {
            // horizontal: choose leftmost cell
            if (by < wy) horiz.emplace_back(bx, by);
            else         horiz.emplace_back(wx, wy);
        } else {
            // vertical: choose bottommost cell
            if (bx < wx) vert.emplace_back(bx, by);
            else         vert.emplace_back(wx, wy);
        }
    }

    // Output horizontal then vertical as per statement
    cout << horiz.size() << "\n";
    for (auto &c : horiz) {
        cout << c.first << " " << c.second << "\n";
    }
    cout << vert.size() << "\n";
    for (auto &c : vert) {
        cout << c.first << " " << c.second << "\n";
    }

    return 0;
}
```

5. Python implementation with detailed comments  
```python
import sys
from collections import deque

def hopcroft_karp(adj, nL, nR):
    """Return (matching_size, pairU, pairV). adj[u] = list of v's."""
    INF = 10**9
    pairU = [-1]*nL
    pairV = [-1]*nR
    dist  = [0]*nL

    def bfs():
        queue = deque()
        # Initialize free left nodes at distance 0
        for u in range(nL):
            if pairU[u] == -1:
                dist[u] = 0
                queue.append(u)
            else:
                dist[u] = INF
        found = False
        while queue:
            u = queue.popleft()
            for v in adj[u]:
                pu = pairV[v]
                if pu == -1:
                    # Found an unmatched right node
                    found = True
                elif dist[pu] == INF:
                    dist[pu] = dist[u] + 1
                    queue.append(pu)
        return found

    def dfs(u):
        for v in adj[u]:
            pu = pairV[v]
            if pu == -1 or (dist[pu] == dist[u]+1 and dfs(pu)):
                pairU[u] = v
                pairV[v] = u
                return True
        dist[u] = INF
        return False

    matching = 0
    while bfs():
        for u in range(nL):
            if pairU[u] == -1 and dfs(u):
                matching += 1
    return matching, pairU, pairV

def main():
    data = sys.stdin.read().split()
    it = iter(data)
    N, P = map(int, (next(it), next(it)))
    removed = set()
    for _ in range(P):
        x, y = map(int, (next(it), next(it)))
        removed.add((x,y))

    total_free = N*N - P
    # If odd free cells, impossible
    if total_free % 2:
        print("No")
        return

    # Partition free cells by parity
    black, white = [], []
    bidx, widx = {}, {}
    for x in range(1, N+1):
        for y in range(1, N+1):
            if (x,y) in removed: continue
            if ((x+y)&1) == 0:
                bidx[(x,y)] = len(black)
                black.append((x,y))
            else:
                widx[(x,y)] = len(white)
                white.append((x,y))

    # Build adjacency list: black → white
    adj = [[] for _ in range(len(black))]
    for i,(x,y) in enumerate(black):
        for dx,dy in [(1,0),(-1,0),(0,1),(0,-1)]:
            nx, ny = x+dx, y+dy
            if (nx,ny) in widx:
                adj[i].append(widx[(nx,ny)])

    # Run Hopcroft–Karp
    match_sz, pairU, pairV = hopcroft_karp(adj, len(black), len(white))
    if match_sz*2 != total_free:
        print("No")
        return

    print("Yes")
    horiz, vert = [], []
    # Extract domino placements
    for bi, wi in enumerate(pairU):
        if wi < 0: continue
        bx, by = black[bi]
        wx, wy = white[wi]
        if bx == wx:
            # horizontal → pick left cell
            if by < wy:
                horiz.append((bx,by))
            else:
                horiz.append((wx,wy))
        else:
            # vertical → pick bottom cell
            if bx < wx:
                vert.append((bx,by))
            else:
                vert.append((wx,wy))

    # Output horizontal then vertical
    print(len(horiz))
    for x,y in horiz:
        print(x, y)
    print(len(vert))
    for x,y in vert:
        print(x, y)

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