#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e9 + 10;
const ll INFL = 4e18;

template <typename Cap>
struct MaxFlow {
    MaxFlow() = default;
    MaxFlow(int n) {
        this->n = n;
        graph = vector<vector<tuple<int, int, Cap>>>(n);
    }
    void add_edge(int u, int v, Cap c) {
        graph[u].push_back(make_tuple(v, graph[v].size(), c));
        graph[v].push_back(make_tuple(u, (int)graph[u].size() - 1, 0));
    }
    Cap get(int start, int goal) {
        Cap ret = 0;
        while (true) {
            vector<int> dst = calculate_distance(start);
            if (dst[goal] < 0) return ret;
            vector<int> removed(n, 0);
            while (true) {
                Cap add = flowing(start, goal, numeric_limits<Cap>::max(), removed, dst);
                if (add == 0) break;
                ret += add;
            }
        }
        return ret;
    }

private:
    int n;
    vector<vector<tuple<int, int, Cap>>> graph;
    vector<int> calculate_distance(int start) {
        vector<int> dst(n, -1);
        dst[start] = 0;
        queue<int> que;
        que.push(start);
        while (!que.empty()) {
            int now = que.front();
            que.pop();
            for (auto [nxt, _, cap] : graph[now]) {
                if (cap > 0 && dst[nxt] == -1) {
                    dst[nxt] = dst[now] + 1;
                    que.push(nxt);
                }
            }
        }
        return dst;
    }
    Cap flowing(int now, int goal, Cap limit, vector<int> &removed, vector<int> &dst) {
        if (now == goal) {
            return limit;
        }
        while (removed[now] < (int)graph[now].size()) {
            auto [nxt, rev, cap] = graph[now][removed[now]];
            if (cap > 0 && dst[now] < dst[nxt]) {
                Cap flow = flowing(nxt, goal, min(limit, cap), removed, dst);
                if (flow > 0) {
                    std::get<2>(graph[now][removed[now]]) -= flow;
                    std::get<2>(graph[nxt][rev]) += flow;
                    return flow;
                }
            }
            removed[now]++;
        }
        return 0;
    }
};

int main() {
    ll N, M;
    cin >> N >> M;
    vector<ll> X(N), Y(N), V;
    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i], V.push_back(X[i]), V.push_back(Y[i]);

    ranges::sort(V);
    V.erase(unique(V.begin(), V.end()), V.end());
    auto get = [&](ll x) { return ranges::lower_bound(V, x) - V.begin(); };
    int S = ssize(V);

    int T = N + S + 2, s = N + S, t = N + S + 1;
    MaxFlow<int> mf(T);
    for (int i = 0; i < N; i++) mf.add_edge(s, i, 1);
    for (int i = N; i < N + S; i++) mf.add_edge(i, t, 1);
    for (int i = 0; i < N; i++) mf.add_edge(i, N + get(X[i]), 1), mf.add_edge(i, N + get(Y[i]), 1);

    cout << mf.get(s, t) << endl;
}