#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pullull;
typedef pair<ll, int> plli;
typedef pair<int, pii> pipii;
typedef vector<vector<int> > mati;
typedef vector<vector<double> > matd;
typedef vector<ll> vll;
typedef vector<vector<ll>> vvll;
typedef vector<vector<vector<ll>>> vvvll;
typedef vector<bool> vb;
typedef vector<vector<bool>> vvb;
typedef vector<vector<vector<bool>>> vvvb;
typedef vector<pll> vpll;
typedef vector<vpll> vvpll;

#define FOR(i,x,y) for(ll i=(ll)x; i<(ll)y; ++i)
#define REP(i,y) FOR(i, 0, y)
#define RFOR(i,x,y) for(ll i=(ll)x; i>=(ll)y; --i)
#define RREP(i,x) RFOR(i, x, 0)
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define debug_printf(x...) cerr << "line " << __LINE__ << " : "; debug_printf_in(x);

template <typename First>
void debug_printf_in(First first){
  cerr << first << endl;
  return;
}

template <typename First, typename... Rest>
void debug_printf_in(First first, Rest... rest){
  cerr << first << " ";
  debug_printf_in(rest...);
  return;
}

void IN(void){
  return;
}

template <typename First, typename... Rest>
void IN(First& first, Rest&... rest){
  cin >> first;
  IN(rest...);
  return;
}

template <typename First>
void OUT(First first){
  cout << first << endl;
  return;
}

template <typename First, typename... Rest>
void OUT(First first, Rest... rest){
  cout << first << " ";
  OUT(rest...);
  return;
}

template<class t, class u> void chmax(t&a,u b){if(a<b)a=b;};
template<class t, class u> void chmin(t&a,u b){if(a>b)a=b;};
int popcount(int t){return __builtin_popcount(t);} //GCC
int popcount(ll t){return __builtin_popcountll(t);} //GCC

template <typename T>
void vec_print(vector<T> VEC){
  REP(i, VEC.size()){
    cout << VEC[i] << " ";
  }
  cout << "\n";
};

template <typename T>
void mat_print(vector<vector<T> > MAT){
  REP(i, MAT.size()){
    REP(j, MAT[i].size()){
      cout << MAT[i][j] << " ";
    }
    cout << "\n";
  }
};

template <typename CLASS1, typename CLASS2>
class HOGE{
  public:
    CLASS1 key;
    CLASS2 value;
    HOGE(void){
      return;
    };
    HOGE(CLASS1 key, CLASS2 value){
      this->key = key;
      this->value = value;
    };
    ~HOGE(void){
      return;
    };

    void print(void){
      cout << "key : " << key << ", value : " << value << "\n";
      return;
    };
    
    bool operator==(const HOGE &obj){
      return (this->value == obj.value);
    };
    bool operator<(const HOGE &obj){
      return (this->value < obj.value);
    };
    bool operator>(const HOGE &obj){
      return (this->value > obj.value);
    };
};

template <typename CLASS1, typename CLASS2>
bool operator==(const HOGE<CLASS1, CLASS2> &hoge1, const HOGE<CLASS1, CLASS2> &hoge2){
  return hoge1.value == hoge2.value;
};

template <typename CLASS1, typename CLASS2>
bool operator<(const HOGE<CLASS1, CLASS2> &hoge1, const HOGE<CLASS1, CLASS2> &hoge2){
  return hoge1.value < hoge2.value;
};

template <typename CLASS1, typename CLASS2>
bool operator>(const HOGE<CLASS1, CLASS2> &hoge1, const HOGE<CLASS1, CLASS2> &hoge2){
  return hoge1.value > hoge2.value;
};

constexpr int INF = (1<<30);
constexpr ll INFLL = 1LL<<62;
constexpr long double EPS = 1e-12;
constexpr ll MOD = (ll)((1E+9)+7);

class Ford_Fulkerson{
  //Ford-Fulkerson algorithm
  //calculation time complexity : O(maxflow*|E|)

  private:
    //structure representing edge (where to go, capacity, reverse)
    struct edge {ll to, cap, rev; };

    vector<vector<edge> > G;
    vector<bool> used;
    ll V;

    // add edge to graph from "from" to "to" with capacity "cap"
    void add_edge(ll from, ll to, ll cap){
      G[from].push_back((edge){to, cap, (ll)G[to].size()});
      G[to].push_back((edge){from, 0, (ll)G[from].size()-1});
    };

    ll dfs(ll v, ll t, ll f){
      if(v==t) return f;
      used[v] = true;
      for(ll i=0; i<G[v].size(); ++i){
        edge &e = G[v][i];
        if(!used[e.to] && e.cap>0){
          ll 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;
    };

  public:
    Ford_Fulkerson(ll V, vector<ll> From, vector<ll> To, vector<ll> Cost){
      this->V = V;
      used.resize(V, false);
      ll E = (ll)From.size();
      if(To.size() != E || Cost.size() != E){
        fprintf(stderr, "Sizes are different, %d %d %d\n", From.size(), To.size(), Cost.size());
        exit(0);
      }
      G.resize(V);

      for(ll i=0; i<E; ++i){
        add_edge(From[i], To[i], Cost[i]);
      }
      return;
    };

    ~Ford_Fulkerson(void){
      return;
    };

    ll max_flow(ll s, ll t){
      ll flow = 0;
      for(;;){
        for(ll i=0; i<V; ++i) used[i] = false;
        ll f = dfs(s, t, INFLL);
        if(f==0) return flow;
        flow += f;
      }
      return flow;
    };
};

int main(){
  cin.tie(0); // cut the cin and cout (default, std::flush is performed after std::cin)
  ios::sync_with_stdio(false); // cut the iostream and stdio (DON'T endl; BUT "\n";)

  ll N;
  IN(N);
  vll a(N), b(N), c(N), d(N);
  REP(i,N) IN(a[i], b[i]); // 1 ~ N
  REP(i,N) IN(c[i], d[i]); // N+1 ~ 2N

  ll V = 2 * N + 2;
  vll From, To, Cost;
  REP(i,N){
    From.pb(0);
    To.pb(i+1);
    Cost.pb(1);
    From.pb(N+1+i);
    To.pb(2*N+1);
    Cost.pb(1);
  }

  REP(i,N){
    REP(j,N){
      if(a[i] < c[j] && b[i] < d[j]){
        From.pb(i+1);
        To.pb(j+1+N);
        Cost.pb(1);
      }
    }
  }

  REP(i,From.size()){
    debug_printf(From[i], To[i], Cost[i]);
  }

  Ford_Fulkerson FF(V, From, To, Cost);

  OUT(FF.max_flow(0, V-1));

  return 0;
}


Measured memory_bytes: 640