#include using namespace std; typedef long long int ll; // 提示されたDinic法ライブラリをそのまま使用 template struct dinic { struct edge { int to; T c, f; }; T eps; const T inf = numeric_limits::max(); int n, m = 0; vector e; vector> g; vector level, ptr; dinic(int n) : n(n), g(n), level(n), ptr(n) { eps = (T)1 / (T)1e9; } void add_edge(int s, int t, T c) { e.push_back({t, c, 0}); e.push_back({s, 0, 0}); g[s].push_back(m++); g[t].push_back(m++); } bool bfs(int s, int t) { fill(level.begin(), level.end(), -1); level[s] = 0; for (queue q({s}); q.size(); q.pop()) { int s = q.front(); for (int i : g[s]) { int t = e[i].to; if (level[t] == -1 and (e[i].c - e[i].f) > eps) { level[t] = level[s] + 1; q.push(t); } } } return (level[t] != -1); } T dfs(int s, int t, T psh) { if (!(psh > eps) or s == t) return psh; for (int &i = ptr[s]; i < (int)g[s].size(); ++i) { auto &eg = e[g[s][i]]; if (level[eg.to] != level[s] + 1 or !(eg.c - eg.f > eps)) continue; T f = dfs(eg.to, t, min(psh, eg.c - eg.f)); if (f > eps) { eg.f += f; e[g[s][i] ^ 1].f -= f; return f; } } return 0; } T max_flow(int s, int t) { T f = 0; while (bfs(s, t)) { fill(ptr.begin(), ptr.end(), 0); while (1) { T c = dfs(s, t, inf); if (c > eps) { f += c; } else { break; } } } return f; } }; int main() { // 入出力の高速化 ios::sync_with_stdio(false); cin.tie(nullptr); int N; ll M; // Mは最大10^18なのでlong long cin >> N >> M; // 入力を保存する配列 vector> requests(N); // 座標圧縮用の配列 (景品の番号を管理) vector prizes; for (int i = 0; i < N; ++i) { cin >> requests[i].first >> requests[i].second; prizes.push_back(requests[i].first); prizes.push_back(requests[i].second); } // 座標圧縮処理 // 景品の番号をソートし、重複を削除する sort(prizes.begin(), prizes.end()); prizes.erase(unique(prizes.begin(), prizes.end()), prizes.end()); // グラフの構築 // ノード構成: // 0 ~ N-1 : bot // N ~ N+K-1 : 景品 (K = uniqueな景品の数) // S : N + K // T : N + K + 1 int K = prizes.size(); int S = N + K; int T = S + 1; dinic g(T + 1); for (int i = 0; i < N; ++i) { // Source -> Bot (容量1: 弾は1発) g.add_edge(S, i, 1); // Bot -> Prize X (座標圧縮後のindexを取得) int idx_x = lower_bound(prizes.begin(), prizes.end(), requests[i].first) - prizes.begin(); // Bot -> Prize Y int idx_y = lower_bound(prizes.begin(), prizes.end(), requests[i].second) - prizes.begin(); // Bot -> Prize (容量1) // 景品ノードは N から始まるため + N する g.add_edge(i, N + idx_x, 1); g.add_edge(i, N + idx_y, 1); } // Prize -> Sink (容量1: 景品は1つにつき1回しか撃ち落とせない) for (int i = 0; i < K; ++i) { g.add_edge(N + i, T, 1); } // 最大流を求めて出力 cout << g.max_flow(S, T) << "\n"; return 0; }