#include<algorithm>//sort,二分探索,など
#include<bitset>//固定長bit集合
#include<cmath>//pow,logなど
#include<complex>//複素数
#include<deque>//両端アクセスのキュー
#include<functional>//sortのgreater
#include<iomanip>//setprecision(浮動小数点の出力の誤差)
#include<iostream>//入出力
#include<iterator>//集合演算(積集合,和集合,差集合など)
#include<map>//map(辞書)
#include<numeric>//iota(整数列の生成),gcdとlcm(c++17)
#include<queue>//キュー
#include<set>//集合
#include<stack>//スタック
#include<string>//文字列
#include<unordered_map>//イテレータあるけど順序保持しないmap
#include<unordered_set>//イテレータあるけど順序保持しないset
#include<utility>//pair
#include<vector>//可変長配列

#define rep(i,n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int,int>;
using ll = long long;
const int INF = 100005;
const int MAX_N = 100005;

bool comp(P a, P b){
    if(a.second != b.second){
        return a.second < b.second;
    }else{
        return a.first < b.first;
    }
}

int n;
int main(){
    cin >> n;
    vector<P> a,b;
    int x,y;
    rep(i,n){
        cin >> x >> y;
        a.push_back(make_pair(x,y));
    }

    rep(i,n){
        cin >> x >> y;
        b.push_back(make_pair(x,y));
    }

    sort(a.rbegin(),a.rend());
    sort(b.begin(),b.end(),comp);

    int count =0;
    

    rep(i,n){
        for(int j=0; j<b.size(); j++){
            if(a[i].first < b[j].first && a[i].second < b[j].second ){
                count ++;
                b.erase(b.begin()+j);
                break;
            }
        }
    }

    cout << count << endl;

}
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <functional>
#include <cmath>
#include <set>
#include <queue>
#include <deque>
#include <vector>
#include <climits>
#include <sstream>
#include <iomanip>
#include <map>
#include <stack>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;

struct EdgeMF
{
	int to;
	ll capacity;
	int reverse;
};

void addEdgeForFlow(vector<vector<EdgeMF>>& G, int from, int to, ll capacity, ll reverseCapacity)
{
	G[from].push_back({ to, capacity, (int)G[to].size() });
	G[to].push_back({ from, reverseCapacity, (int)G[from].size() - 1 });
}

ll dfsForFlow(vector<vector<EdgeMF>>& G, vector<bool>& used, int u, int t, ll f)
{
	if (u == t)
	{
		return f;
	}

	used[u] = true;
	for (auto& e : G[u])
	{
		if (used[e.to] || e.capacity <= 0)
		{
			continue;
		}

		auto d = dfsForFlow(G, used, e.to, t, min(f, e.capacity));
		if (d > 0)
		{
			e.capacity -= d;
			G[e.to][e.reverse].capacity += d;
			return d;
		}
	}

	return 0;
}

ll calcMaxFlow(vector<vector<EdgeMF>>& G, int s, int t)
{
	auto f = 0ll;
	while (true)
	{
		vector<bool> used((int)G.size());
		auto d = dfsForFlow(G, used, s, t, LLONG_MAX);
		if (d <= 0)
		{
			break;
		}
		f += d;
	}

	return f;
}


int main()
{
	int N;
	cin >> N;
	vector<int> x(2 * N);
	vector<int> y(2 * N);
	for (auto i = 0; i < 2 * N; ++i)
	{
		cin >> x[i] >> y[i];
	}

	vector<vector<EdgeMF>> G(2 * N + 2);
	for (auto i = 0; i < N; ++i)
	{
		for (auto j = N; j < 2 * N; ++j)
		{
			if (x[i] < x[j] && y[i] < y[j])
			{
				addEdgeForFlow(G, i, j, 1, 0);
			}
		}
	}
	int s = 2 * N;
	int t = s + 1;
	for (auto i = 0; i < N; ++i)
	{
		addEdgeForFlow(G, s, i, 1, 0);
		addEdgeForFlow(G, i + N, t, 1, 0);
	}

	cout << calcMaxFlow(G, s, t) << endl;

	return 0;
}