// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

using ld = long double;

using vi = vector<int>;

using vvi = vector<vi>;

using vvvi = vector<vvi>;

using vll = vector<ll>;

using vvll = vector<vll>;

using vvvll = vector<vvll>;

using vs = vector<string>;

using pll = pair<ll, ll>;

using vp = vector<pll>;

#define rep(i, n) for(ll i = 0; i < (n); i++)

#define repr(i, a, b) for(ll i = (a); i < (b); i++)

#define ALL(a) (a).begin(), (a).end()

#define SZ(x) ((ll)(x).size())

const ll MOD = 1000000007;

inline ll GCD(ll a, ll b){ return b?GCD(b, a % b):a; }

inline ll LCM(ll a, ll b){ return a/GCD(a, b)*b; }

inline ll powint(unsigned long long x, ll y){ ll r=1; while(y){ if(y&1) r*=x; x*=x; y>>=1; } return r; }

inline ll powmod(ll x, ll y, ll m = MOD){ ll r=1; while(y){ if(y&1) r*=x; x*=x; r%=m; x%=m; y>>=1; } return r; }

template<class T>bool chmax(T &a, const T &b){ if(a<b) { a=b; return 1; } return 0; }

template<class T>bool chmin(T &a, const T &b){ if(b<a) { a=b; return 1; } return 0; }

#ifdef OJ_LOCAL

#include "dump.hpp"

#else

#define dump(...) ((void)0)

#endif



struct edge{

    int to, cap, rev;

};



const int MAX_V = 5010;

const int INF = 1000000000;



// 入力

int N, R;

vector<edge> G[MAX_V];  // グラフの隣接リスト表現

bool used[MAX_V];       // DFSですでに調べたかのフラグ



// fromからtoへ向かう容量capの辺をグラフに追加する

void add_edge(int from, int to, int cap){

    G[from].push_back((edge){to, cap, G[to].size()});

    G[to].push_back((edge){from, 0, int(G[from].size())-1});

}



// 増加パスをDFSで探す

int dfs(int v, int t, int f){

    if(v == t) return f;

    used[v] = true;

    for(int i = 0; i < int(G[v].size()); i++){

        edge &e = G[v][i];

        if(!used[e.to] && e.cap > 0){

            int d = dfs(e.to, t, min(f, e.cap));

            if(d > 0){

                e.cap -= d;

                G[e.to][e.rev].cap += d;

                return d;

            }

        }

    }

    return 0;

}



// sからtへの最大流を求める

// O(FE) 小さい定数倍

int max_flow(int s, int t){

    int flow = 0;

    for(;;){

        memset(used, 0, sizeof(used));

        int f = dfs(s, t, INF);

        if(f == 0) return flow;

        flow += f;

    }

}





int main(){

    cin.tie(0); ios::sync_with_stdio(false);

    cout << fixed << setprecision(15);

    ll n;

    cin >> n;

    vll a(n), b(n);

    rep(i, n){

        cin >> a[i] >> b[i];

    }

    vll c(n), d(n);

    rep(i, n){

        cin >> c[i] >> d[i];

    }

    

    // 二部マッチング

    rep(i, n)rep(j, n){

        if(a[i] < c[j] && b[i] < d[j]){

            add_edge(i, 5*n+j, 1);

        }

    }

    rep(i, n){

        add_edge(122, i, 1);

    }

    rep(i, n){

        add_edge(5*n+i, 800, 1);

    }

    rep(i, MAX_V){

        for(auto&& e: G[i]){

            //cout << e.to << " " << e.cap << " " << e.rev << endl;

        }

    }

    cout << max_flow(122, 800) << endl;

    return 0;

}

// Optimized solution to the same problem (faster):
#pragma region template

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

using ull = unsigned long long;

using ld = long double;

using vi = vector<int>;

using vvi = vector<vi>;

using vvvi = vector<vvi>;

using vll = vector<ll>;

using vvll = vector<vll>;

using vvvll = vector<vvll>;

using vld = vector<ld>;

using vvld = vector<vld>;

using vvvld = vector<vvld>;

using vs = vector<string>;

using pll = pair<ll, ll>;

using vp = vector<pll>;

template <typename T>

using pqrev = priority_queue<T, vector<T>, greater<T>>;

#define rep(i, n) for (ll i = 0, i##_end = (n); i < i##_end; i++)

#define repb(i, n) for (ll i = (n)-1; i >= 0; i--)

#define repr(i, a, b) for (ll i = (a), i##_end = (b); i < i##_end; i++)

#define reprb(i, a, b) for (ll i = (b)-1, i##_end = (a); i >= i##_end; i--)

#define ALL(a) (a).begin(), (a).end()

#define SZ(x) ((ll)(x).size())

//*

constexpr ll MOD = 1e9 + 7;

/*/

constexpr ll MOD = 998244353;

//*/

constexpr ll INF = 1e+18;

constexpr ld EPS = 1e-12L;

constexpr ld PI = 3.14159265358979323846L;

constexpr ll GCD(ll a, ll b) { return b ? GCD(b, a % b) : a; }

constexpr ll LCM(ll a, ll b) { return a / GCD(a, b) * b; }

template <typename S, typename T>

inline bool chmax(S &a, const T &b) {

  if (a < b) {

    a = b;

    return 1;

  }

  return 0;

}

template <typename S, typename T>

inline bool chmin(S &a, const T &b) {

  if (b < a) {

    a = b;

    return 1;

  }

  return 0;

}

#ifdef OJ_LOCAL

#include "dump.hpp"

#else

#define dump(...) ((void)0)

#endif

template <typename T>

bool print_(const T &a) {

  cout << a;

  return true;

}

template <typename T>

bool print_(const vector<T> &vec) {

  for (auto &a : vec) {

    cout << a;

    if (&a != &vec.back()) {

      cout << " ";

    }

  }

  return false;

}

template <typename T>

bool print_(const vector<vector<T>> &vv) {

  for (auto &v : vv) {

    for (auto &a : v) {

      cout << a;

      if (&a != &v.back()) {

        cout << " ";

      }

    }

    if (&v != &vv.back()) {

      cout << "\n";

    }

  }

  return false;

}

void print() { cout << "\n"; }

template <typename Head, typename... Tail>

void print(Head &&head, Tail &&... tail) {

  bool f = print_(head);

  if (sizeof...(tail) != 0) {

    cout << (f ? " " : "\n");

  }

  print(forward<Tail>(tail)...);

}

#pragma endregion



// v1をソートし、v2を対応する位置に移動する

template <typename T, typename U>

void pairSort(vector<T> &v1, vector<U> &v2, bool rev = false) {

  int n = v1.size();

  vector<pair<T, U>> p(n);

  for (int i = 0; i < n; i++) {

    p[i] = pair<T, U>(v1[i], v2[i]);

  }

  if (rev) {

    sort(p.begin(), p.end(), [&](const auto &l, const auto &r) {

      if (l.first == r.first)

        return l.second > r.second;

      else

        return l.first < r.first;

    });

  } else {

    sort(p.begin(), p.end());

  }

  for (int i = 0; i < n; i++) {

    v1[i] = p[i].first;

    v2[i] = p[i].second;

  }

}





int main() {

  cin.tie(0);

  ios::sync_with_stdio(false);

  cout << fixed << setprecision(20);

  ll n;

  cin >> n;

  vll a(n), b(n);

  rep(i, n){

    cin >> a[i] >> b[i];

  }

  vll c(n), d(n);

  rep(i, n){

    cin >> c[i] >> d[i];

  }

  pairSort(c, d);

  vi f(n, 1);

  rep(i, n){

    ll id = -1;

    ll pos = -INF;

    rep(j, n){

      if(f[j] && a[j] < c[i] && b[j] < d[i]){

        if(chmax(pos, b[j])){

          id = j;

        }

      }

    }

    if(id != -1){

      f[id] = 0;

    }

  }

  print(n - accumulate(ALL(f), 0));

}


// Fastest known solution for this problem: