#include <iostream>
#include <iomanip>
#include <tuple>
#include <map>
#include <queue>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <limits>
using namespace std;
void init();
#ifdef DEBUG_BUILD
#define DBG(expr) cout << #expr << " = " << expr << endl;
#endif
#define ECHO(expr) cout << expr << endl;
#define REP(var, num) for(ll var = 0; var < num; var++)
#define REP_FROM(var, from, num) for(ll var = from; var < num; var++)
#define MAX_OF(type) numeric_limits<type>::max()
#define MIN_OF(type) numeric_limits<type>::min()
#define SORT(vec) sort(vec.begin(), vec.end())
#define REVERSE(vec) reverse(vec.begin(), vec.end())
#define ALL(vec) vec.begin(), vec.end()
#define T_FIRST(tuple) (std::get<0>(tuple))
#define T_SECOND(tuple) (std::get<1>(tuple))
#define T_THIRD(tuple) (std::get<2>(tuple))
typedef signed long long ll;
typedef unsigned long long ull;
class Edge {
public:
    ll src, dst, cap, rev;
    Edge(ll src, ll dst, ll cap, ll rev) : src(src), dst(dst), cap(cap), rev(rev) {}
};

class Dinic {
    ll num_nodes;
    vector<vector<Edge> > edges;
    vector<ll> distances;
    vector<ll> visited;

public:
    Dinic(ll num_nodes)
        : num_nodes(num_nodes)
        , edges(num_nodes)
        , distances(num_nodes, -1)
        , visited(num_nodes)
        {}

    void add_edge(ll src, ll dst, ll cap) {
        edges[src].emplace_back(src, dst, cap, edges[dst].size());
        edges[dst].emplace_back(dst, src, 0, edges[src].size() - 1);
    }

    ll max_flow(ll start, ll goal) {
        ll ans = 0;
        while (true) {
            bfs(start);
            if (distances[goal] < 0) {
                return ans;
            }

            visited.assign(num_nodes, 0);
            ll f;
            while ((f = dfs(start, goal, MAX_OF(ll))) > 0)
                ans += f;
        }
    }

private:
    // Computes the distances between `start` and each nodes whose
    // current capacity is not 0.
    void bfs(ll start) {
        distances.assign(num_nodes, -1);
        distances[start] = 0;
        queue<ll> qs;
        qs.push(start);
        while (!qs.empty()) {
            ll v = qs.front(); qs.pop();
            for (Edge& e: edges[v]) {
                if (e.cap > 0 && distances[e.dst] < 0) {
                    distances[e.dst] = distances[v] + 1;
                    qs.push(e.dst);
                }
            }
        }
    }

    ll dfs(ll src, ll dst, ll flow) {
        if (src == dst)
            return flow;

        for (ll& i = visited[src]; i < (ll) edges[src].size(); i++) {
            Edge& e = edges[src][i];
            if (e.cap > 0 && distances[src] < distances[e.dst]) {
                ll f = dfs(e.dst, dst, min(flow, e.cap));
                if (f > 0) {
                    e.cap -= f;
                    edges[e.dst][e.rev].cap += f;
                    return f;
                }
            }
        }

        return 0;
    }
};

void solve() {
    ll n;
    cin >> n;
    Dinic graph(2*n+3);
    vector<tuple<int, int, int> > reds(n);
    vector<tuple<int, int, int> > blues(n);
    REP(i, n) {
        ll a, b;
        cin >> a >> b;
        reds[i] = make_tuple(a, b, i);
        graph.add_edge(2*n+1, i, 1);
    }
    REP(i, n) {
        ll a, b;
        cin >> a >> b;
        blues[i] = make_tuple(a, b, i+n);
        graph.add_edge(i+n, 2*n+2, 1);
    }

    SORT(reds);
    SORT(blues);

    for (auto& r: reds) {
//        printf("r[] = (%lld, %lld)\n", T_FIRST(r), T_SECOND(r));
        for (auto& b: blues) {
//            printf("b[] = (%lld, %lld)\n", T_FIRST(b), T_SECOND(b));
            if (T_FIRST(r) < T_FIRST(b) && T_SECOND(r) < T_SECOND(b)) {
                graph.add_edge(T_THIRD(r), T_THIRD(b), 1);
            }
        }
    }

    ECHO(graph.max_flow(2*n+1, 2*n+2))
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

#ifdef INPUT_FILE
    if (!freopen(INPUT_FILE, "r", stdin)) {
        perror("freopen");
        exit(1);
    }
#endif

    solve();
    return 0;
}

Measured memory_bytes: 512