// May this submission get accepted!

#pragma GCC optimize ("O3")
#pragma GCC target ("tune=native")
#pragma GCC target ("avx")

#include <bits/stdc++.h>

// 汎用マクロ
#define ALL_OF(x) (x).begin(), (x).end()
#define REP(i,n) for (long long i=0, i##_len=(n); i<i##_len; i++)
#define RANGE(i,is,ie) for (long long i=(is), i##_end=(ie); i<=i##_end; i++)
#define DSRNG(i,is,ie) for (long long i=(is), i##_end=(ie); i>=i##_end; i--)
#define STEP(i, is, ie, step) for (long long i=(is), i##_end=(ie), i##_step = (step); i<=i##_end; i+=i##_step)
#define UNIQUE(v) do { sort((v).begin(), (v).end()); (v).erase(unique((v).begin(), (v).end()), (v).end()); } while (false)
template<class T> bool chmax(T &a, const T &b) { if (a < b) {a = b; return true;} return false; }
template<class T> bool chmin(T &a, const T &b) { if (a > b) {a = b; return true;} return false; }
#define INF 0x7FFFFFFF
#define LINF 0x7FFFFFFFFFFFFFFFLL
#define Yes(q) ((q) ? "Yes" : "No")
#define YES(q) ((q) ? "YES" : "NO")
#define Possible(q) ((q) ? "Possible" : "Impossible")
#define POSSIBLE(q) ((q) ? "POSSIBLE" : "IMPOSSIBLE")
#define DUMP(q) cerr << "[DEBUG] " #q ": " << (q) << " at " __FILE__ ":" << __LINE__ << endl
#define DUMPALL(q) do { cerr << "[DEBUG] " #q ": ["; REP(DUMPALL_ITR, (q).size()) { cerr << (q)[DUMPALL_ITR] << (DUMPALL_ITR == DUMPALL_ITR_len-1 ? "" : ", "); } cerr << "] at " __FILE__ ":" << __LINE__ << endl; } while (false)
template<class T> T gcd(T a, T b) { if (a < b) std::swap(a, b); while (b) std::swap(a %= b, b); return a; }
template<class T> T lcm(const T a, const T b) { return a / gcd(a, b) * b; }

// gcc拡張マクロ
#define popcount __builtin_popcount
#define popcountll __builtin_popcountll

// エイリアス
#define DANCE_ long
#define ROBOT_ unsigned
#define HUMAN_ signed
using  ll = DANCE_ HUMAN_ DANCE_;
using ull = DANCE_ ROBOT_ DANCE_;
using  ld = long double;
using namespace std;

// 標準入出力
struct inp {
    size_t sz;
    inp(size_t _sz = 1) : sz(_sz) {}
    template <typename T> operator T () const { T a; cin >> a; return a; }
    template <typename T> operator vector<T> () const { vector<T> a(sz); for (size_t i = 0; i < sz; i++) cin >> a[i]; return a; }
};
inp inp1; // input one
template <typename T> void say(T &x, char end = '\n') { cout << x << end; }
template <typename T> void say(vector<T> &x, char sep = ' ', char end = '\n') { for (size_t i = 0, sz = x.size(); i < sz; i++) { cout << x[i] << (i == sz-1 ? end : sep); } }

// モジュール

// Диниц 法による最大フロー O(V^2 E)
// T: 容量の型 (整数型でないと無限ループする可能性がある)
template <typename flow_t>
struct dinic {
    
    struct edge {
        size_t to;
        flow_t cap;
        size_t rev;
        edge(size_t _to, flow_t _cap, size_t _rev) :
            to(_to), cap(_cap), rev(_rev) {}
    };

    size_t n;
    vector<vector<edge>> g;
    vector<int> min_cost, iter;

    dinic(size_t _n) :
        n(_n), g(n), min_cost(n), iter(n) {}

    void add_arc(size_t from, size_t to, flow_t cap) {
        assert(0 <= from && from < n);
        assert(0 <= to   && to   < n);
        g[from].emplace_back(to  , cap, g[to  ].size());
        g[to  ].emplace_back(from,   0, g[from].size() - 1);
    }
    
    void add_edge(size_t from, size_t to, flow_t cap) {
        add_arc(from, to, cap);
        add_arc(to, from, cap);
    }

    bool bfs(size_t s, size_t t) {
        min_cost.assign(n, -1);
        deque<size_t> q;
        min_cost[s] = 0;
        q.push_back(s);
        while (q.size() && min_cost[t] == -1) {
            size_t p = q.front(); q.pop_front();
            for (edge &e : g[p]) {
                if (e.cap > 0 && min_cost[e.to] == -1) {
                    min_cost[e.to] = min_cost[p] + 1;
                    q.push_back(e.to);
                }
            }
        }
        return min_cost[t] != -1;
    }

    flow_t dfs(size_t idx, const size_t t, flow_t flow) {
        if (idx == t) return flow;
        for (int &i = iter[idx]; i < g[idx].size(); i++) {
            edge &e = g[idx][i];
            if (e.cap > 0 && min_cost[idx] < min_cost[e.to]) {
                flow_t d = dfs(e.to, t, min(flow, e.cap));
                if (d > 0) {
                    e.cap -= d;
                    g[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    flow_t max_flow(size_t s, size_t t) {
        assert(0 <= s && s < n);
        assert(0 <= t && t < n);
        const flow_t TINF = numeric_limits<flow_t>::max();
        flow_t flow = 0;
        while (bfs(s, t)) {
            iter.assign(n, 0);
            flow_t f = 0;
            while ((f = dfs(s, t, TINF)) > 0) flow += f;
        }
        return flow;
    }

};

// 処理内容
int main() {
    
    // インタラクティブ問題では除去した方がいいかも
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    ll n = inp1;
    vector<ll> a(n), b(n), c(n), d(n);
    REP(i, n) {
        a[i] = inp1;
        b[i] = inp1;
    }
    REP(i, n) {
        c[i] = inp1;
        d[i] = inp1;
    }

    dinic<ll> g(n*2+2);

    REP(i, n) g.add_arc(0, i+1, 1);
    REP(i, n) g.add_arc(n+1+i, n*2+1, 1);
    
    REP(i, n) REP(j, n) {
        if (a[i] < c[j] && b[i] < d[j]) {
            g.add_arc(i+1, n+1+j, 1);
        }
    }
    ll ans = g.max_flow(0, n*2+1);
    say(ans);
    
}

Measured memory_bytes: 512