#include<cstdio>
#include<cmath>
#include<cstring>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#define LL long long
#define ll __int64
#define INF 0x3f3f3f3f
#define mem(x) memset(x,0,sizeof(x))
#define PI acos(-1)
#define eps 1e-10
#define si(n) scanf("%d",&n)
#define sll(n) scanf("%lld",&n)
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}


/*
    1.Shoud it use long long ?
    2.Have you ever test several sample(at least three) yourself?
    3.Can you promise that the solution is right? At least,the main ideal
    4.use the puts("") or putchar() or printf and such things?
    5.init the used array or any value?
    6.use error MAX_VALUE?
    7.use scanf instead of cin/cout?
    8.whatch out the detail input require
*/
const int maxn=1e3+5;
int m[maxn][maxn];
int n;
struct node
{
	int x,y;
}a[maxn],b[maxn];
int used[maxn];
int match[maxn];
bool dfs(int u)
{
	for(int i=1;i<=n;i++)
	{
		if(!used[i]&&m[u][i])
		{
			used[i]=1;
			if(match[i]==-1||dfs(match[i]))
			{
				match[i]=u;
				return 1;
			}
		}
	}
	return 0;
}
int hungry()
{
	int ans=0;
	memset(match,-1,sizeof(match));
	for(int i=1;i<=n;i++)
	{
		mem(used);
		if(dfs(i)) ++ans;
	}
	return ans;
} 

int main()
{
	si(n);
	for(int i=1;i<=n;i++)
	{
		si(a[i].x);si(a[i].y);
	}
	for(int i=1;i<=n;i++)
	{
		si(b[i].x);si(b[i].y);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i].x<b[j].x&&a[i].y<b[j].y)
			{
				m[i][j+n]=1;
				//m[j+n][i]=1;
			}
		}
	}
	n+=n;
	printf("%d\n",hungry());
}




