#include <bits/stdc++.h>
/*
  _   _     _____
 /'\_/`\   /\  __`\
/\      \  \ \ \/\ \
\ \ \__\ \  \ \ \ \ \
 \ \ \_/\ \  \ \ \_\ \
  \ \_\\ \_\  \ \_____\
   \/_/ \/_/   \/_____/
*/
#define io ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define ll long long
#define ld long double
#define EPS (1e-15)
#define mod 1000000007
#define pii pair<ll, ll>
#define piii pair<ll, pii>
#define SIZE(x) (int) x.size()
#define to_string(x) static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x)).str()
#define lp(i, a, n) for (int(i) = (a); (i) <= (int)(n); ++(i))
#define lpd(i, n, a) for (int(i) = (n); (i) >= (a); --(i))
#define bitcount(n) __builtin_popcountll(n)
#define readi(x) scanf("%d", &x);
#define readl(x) scanf("%lld", &x);
#define reads(x) scanf("%s", &x);
#define readc(x) scanf("%c", &x);
#define readd(x) scanf("%lf", &x);

using namespace std;
const int N = 1000006;
const int K = (int)log2(N) + 2;
const int SQRTN = (int) sqrt(N) + 7;
const ll infi = 1ll << 60;
ll n, x, y;
vector<pii> as, bs;

bool ok(pii v, pii u) {
    return v.first < u.first && v.second < u.second;
}

struct Edge {
    ll from, to, cap, flow, index;
    Edge(ll from, ll to, ll cap, ll flow, ll index) :
    from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct Dinic {
    int N;
    vector<vector<Edge>> G;
    vector<Edge *> dad;
    vector<ll> Q;

    Dinic(int N) : N(N), G(N), dad(N), Q(N) {}

    void addEdge(ll from, ll to, ll cap) {
        G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
        if (from == to)
            G[from].back().index++;
        G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
    }

    ll BlockingFlow(ll s, ll t) {
        fill(dad.begin(), dad.end(), (Edge *) NULL);
        dad[s] = &G[0][0] - 1;
        ll head = 0, tail = 0;
        Q[tail++] = s;
        while (head < tail) {
            ll x = Q[head++];
            for (int i = 0; i < SIZE(G[x]); i++) {
                Edge &e = G[x][i];
                if (!dad[e.to] && e.cap - e.flow > 0) {
                    dad[e.to] = &G[x][i];
                    Q[tail++] = e.to;
                }
            }
        }
        if (!dad[t])
            return 0;
        ll totflow = 0;
        for (int i = 0; i < SIZE(G[t]); i++) {
            Edge *start = &G[G[t][i].to][G[t][i].index];
            ll amt = 1ll << 60;
            for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                if (!e) {
                    amt = 0;
                    break;
                }
                amt = min(amt, e->cap - e->flow);
            }
            if (amt == 0)
                continue;
            for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                e->flow += amt;
                G[e->to][e->index].flow -= amt;
            }
            totflow += amt;
        }
        return totflow;
    }

    ll GetMaxFlow(ll s, ll t) {
        ll totflow = 0;
        while(ll flow = BlockingFlow(s, t))
            totflow += flow;
        return totflow;
    }
};

int main() {
//  freopen("input.txt", "r", stdin);
//  freopen("output.txt", "w", stdout);
    io;
    cin >> n;
    lp (i, 0, n - 1) {
        cin >> x >> y;
        as.push_back({x, y});
    }
    lp (i, 0, n - 1)  {
        cin >> x >> y;
        bs.push_back({x, y});
    }
    Dinic flow(2 * n + 2);
    lp (i, 1, n)
        flow.addEdge(0, i, 1), flow.addEdge(n + i, 2 * n + 1, 1);
    lp (i, 0, n - 1)
        lp (j, 0, n - 1)
            if (ok(as[i], bs[j]))
                flow.addEdge(i + 1, n + j + 1, 1);
    cout << flow.GetMaxFlow(0, 2 * n + 1) << endl;
    return 0;
}


Measured memory_bytes: 640