// 二部マッチング
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_7_A
// https://beta.atcoder.jp/contests/abc091/tasks/arc092_a
import std.stdio, std.algorithm, std.string, std.conv, std.array, std.range, std.math;
int readint() { return readln.chomp.to!int; }
int[] readints() { return readln.split.to!(int[]); }

void main() {
    struct Point { int x, y; }
    int n = readint();
    auto ps = new Point[2 * n];
    foreach (ref p ; ps) readf("%d %d\n", &p.x, &p.y);

    auto bm = new BipartiteMatching();
    int s = 2 * n, t = s + 1;
    foreach (i; 0..n) {
        bm.add_edge(s, i, 1);
        bm.add_edge(n + i, t, 1);
    }
    foreach (i; 0..n) foreach (j; 0..n) {
        if (ps[i].x < ps[n + j].x && ps[i].y < ps[n + j].y)
            bm.add_edge(i, n + j, 1);
    }

    writeln(bm.max_flow(s, t));
    auto _ = readln(); // dbg
}

class BipartiteMatching {
    immutable int INF = 114514810;
    immutable int VMAX = 300;

    struct Edge { int to, cap, rev; }
    Edge[][] G;
    bool[] used; // dfs したか

    this() {
        used.length = G.length = VMAX;
    }

    void add_edge(int from, int to, int cap) {
        G[from] ~= Edge(to, cap, G[to].length.to!int);
        G[to]   ~= Edge(from, 0, G[from].length.to!int - 1);
    }
    // 増加パスを探す
    int dfs(int v, int t, int f) {
        if (v == t) return f;
        used[v] = true;
        foreach (ref e; G[v]) if (!used[e.to] && e.cap > 0) {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
        return 0;
    }
    int max_flow(int s, int t) {
        int flow;
        while (1) {
            fill(used, false);
            int f = dfs(s, t, INF);
            if (f == 0) return flow;
            flow += f;
        }
        assert(false);
    }
}