#include <bits/stdc++.h>
#define pq priority_queue
using namespace std; typedef pair<int, int> P; typedef pair<int, P> P2;
typedef pair<int, P2> P3; typedef long long ll; typedef long double ld;
constexpr long long gcd(long long a, long long b){return b ? gcd(b, a % b) : a;}
constexpr long long lcm(long long a, long long b){return a / gcd(a, b) * b;}
constexpr int INF = 1e9, MOD = INF + 7, around[] = {0, 1, 1, -1, -1, 0, -1, 1, 0, 0};
constexpr int mod_pow(long long x, long long n, const int mod){long long ret=1;while(n){if(n&1)(ret*=x)%=mod;(x*=x)%=mod;n>>=1;}return ret;}
template<int n> struct Prime{bool arr[n+1];constexpr bool operator[](int k){return arr[k];}constexpr Prime():arr(){for(int i=2;i<n;i++){arr[i]=true;for(int j=2;j*j<=i;j++){if(!(i%j))arr[i]=false;}}}};
template<int n> struct Factorial{long long arr[n+1],ary[n+1];constexpr Factorial():arr(),ary(){arr[0]=1;ary[0]=1;for(int i=0;i<n;i++){arr[i+1]=arr[i]*(i+1)%MOD;ary[i+1]=mod_pow(arr[i+1],MOD-2,MOD);}}};
constexpr Factorial<10> fact; constexpr Prime<10> prime;
constexpr int comb(int a, int b){long long pos = fact.arr[a], pot = fact.ary[a - b], por = fact.ary[b];return pos * pot % MOD * por % MOD;}
template<int n> struct Bernoulli{long long arr[n+1];constexpr Bernoulli():arr(){arr[0]=1;for(int i=1;i<=n;i++){long long sum=0;for(int j=0;j<i;j++){(sum+=comb(i+1,j)*arr[j]%MOD)%=MOD;}arr[i]=(MOD-mod_pow(i+1,MOD-2,MOD))%MOD*sum%MOD;}}};
constexpr int vx[] = {1, 0, -1, 0}, vy[] = {0, 1, 0, -1};
constexpr int sqrtN = 512, logN = 32;
constexpr ld PI = abs(acos(-1));
constexpr ll LINF=1e18;

template<typename T>
struct Dinic{
	struct edge{
		int to;
		T cap;
		int rev;
	};
	
	const T INF;
	vector<vector<edge>> g;
	vector<T> min_cost;
	vector<int> itr;
	
	Dinic(int n) : INF(numeric_limits<T>::max()){
		g.resize(n);
	}
	
	void add_edge(int from, int to, T cap){
		g[from].push_back(edge{to, cap, (int)g[to].size()});
		g[to].push_back(edge{from, 0, (int)g[from].size() - 1});
	}
	
	bool bfs(int s, int t){
		min_cost.assign(g.size(), -1);
		queue<int> qu; qu.push(s); min_cost[s] = 0;
		
		while(!qu.empty()){
			auto p = qu.front(); qu.pop();
			
			for(auto e:g[p]){
				if(e.cap <= 0 or min_cost[e.to] != -1) continue;
				min_cost[e.to] = min_cost[p] + 1;
				qu.push(e.to);
			}
		}
		
		return min_cost[t] != -1;
	}
	
	T dfs(int idx, const int t, T flow){
		if(idx == t) return flow;
		for(int &i = itr[idx]; i < g[idx].size(); i++){
			edge &e = g[idx][i];
			
			if(e.cap <= 0 or min_cost[idx] >= min_cost[e.to]) continue;
			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;
	}
	
	T max_flow(int s, int t){
		T flow = 0;
		while(bfs(s, t)){
			itr.assign(g.size(), 0);
			T f = 0;
			while((f = dfs(s, t, INF)) > 0) flow += f;
		}

		return flow;
	}
};

int a[110], b[110], c[110], d[110], n;

int main(){
	cin >> n;
	Dinic<int> flow(3 * n);
	for(int i = 0; i < n; i++) cin >> a[i] >> b[i];
	for(int i = 0; i < n; i++) cin >> c[i] >> d[i];
	
	for(int i = 0; i < n; i++) flow.add_edge(2 * n + 1, i, 1);
	for(int i = 0; i < n; i++) flow.add_edge(n + i, 2 * n, 1);
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			if(a[i] < c[j] and b[i] < d[j]){
				flow.add_edge(i, n + j, 1);
			}
		}
	}
	
	cout << flow.max_flow(2 * n + 1, 2 * n) << endl;
	return 0;
}


Measured memory_bytes: 384