#include <bits/stdc++.h>

#define VARNAME(x) #x
#define show(x) cerr << #x << " = " << x << endl

using namespace std;
using ll = long long;
using ld = long double;

constexpr ll MOD = 1000000007LL;

template <typename T>
constexpr T INF = numeric_limits<T>::max() / 10;

class Flow
{
public:
    using T = ll;
    struct Edge
    {
        Edge(const int from_, const int to_, const int reverse_, const T capacity_, bool is_reverse = false)
            : from{from_}, to{to_}, reverse{reverse_}, capacity{capacity_}, flow{0}, is_reverse(is_reverse) {}
        int from;
        int to;
        int reverse;
        T capacity;
        T flow;
        bool is_reverse;
    };

    Flow(const int v)
        : V{v}, edge(v) {}
    void addEdge(const int from, const int to, const T capacity)
    {
        edge[from].push_back(Edge{from, to, (int)edge[to].size(), capacity, false});
        edge[to].push_back(Edge{to, from, (int)edge[from].size() - 1, 0, true});
    }

    T FordFulkerson(const int s, const int t)
    {
        vector<bool> checked(V);
        T flow = 0;
        while (true) {
            for (int i = 0; i < V; i++) {
                checked[i] = false;
            }
            const T f = dfs_ff(s, t, INF<T>, checked);
            if (f == 0) {
                break;
            }
            flow += f;
        }
        return flow;
    }

    T Dinic(const int s, const int t)
    {
        T flow = 0;
        while (true) {
            vector<int> level(V, -1);
            queue<int> q;
            q.push(s);
            level[s] = 0;
            while (not q.empty()) {
                const int v = q.front();
                for (const auto& e : edge[s]) {
                    if (e.capacity > e.flow and level[e.to] < 0) {
                        level[e.to] = level[v] + 1;
                        q.push(e.to);
                    }
                }
            }
            while (true) {
                const T f = dfs_dinic(s, t, INF<T>, level);
                if (f == 0) {
                    break;
                }
                flow += f;
            }
        }
    }

    const int V;
    vector<vector<Edge>> edge;

private:
    T dfs_ff(const int pos, const int t, const T flow, vector<bool>& checked)
    {
        if (pos == t) {
            return flow;
        }
        checked[pos] = true;
        for (auto& e : edge[pos]) {
            if (not checked[e.to]) {
                const T res = e.capacity - e.flow;
                if (res > 0) {
                    const T d = dfs_ff(e.to, t, min(flow, res), checked);
                    if (d > 0) {
                        e.flow += min(d, res);
                        edge[e.to][e.reverse].flow -= min(d, res);
                        return d;
                    }
                }
            }
        }
        return 0;
    }

    T dfs_dinic(const int pos, const int t, const T flow, const vector<int>& level)
    {
        if (pos == t) {
            return flow;
        }
        for (auto& e : edge[pos]) {
            const T res = e.capacity - e.flow;
            if (res > 0 and level[pos] < level[e.to]) {
                const T d = dfs_dinic(e.to, t, min(flow, res), level);
                if (d > 0) {
                    e.flow += min(d, res);
                    edge[e.to][e.reverse].flow -= min(d, res);
                    return d;
                }
            }
        }
        return 0;
    }
};

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N;
    cin >> N;
    Flow f(2 * N + 2);
    const int S = 2 * N;
    const int T = 2 * N + 1;
    using P = pair<int, int>;
    vector<P> r(N);
    vector<P> b(N);
    for (int i = 0; i < N; i++) {
        int x, y;
        cin >> x >> y;
        r[i] = {x, y};
    }
    for (int i = 0; i < N; i++) {
        int x, y;
        cin >> x >> y;
        b[i] = {x, y};
    }
    for (int i = 0; i < N; i++) {
        f.addEdge(S, i, 1);
    }
    for (int i = 0; i < N; i++) {
        f.addEdge(i + N, T, 1);
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (r[i].first < b[j].first and r[i].second < b[j].second) {
                f.addEdge(i, j + N, 1);
            }
        }
    }
    cout << f.FordFulkerson(S, T) << endl;
    return 0;
}


Measured memory_bytes: 640