# -*- coding: utf-8 -*-



"""

参考：https://www.hamayanhamayan.com/entry/2018/03/18/085108

　　　http://vartkw.hatenablog.com/entry/2016/12/02/002703

　　　https://ikatakos.com/pot/programming_algorithm/graph_theory/maximum_flow

・二部最大マッチング

・最大流アルゴリズム(Dinic法)

・まだ理解不十分な点はあると思うけど、初めて見た時よりは見慣れた。

"""



from collections import deque



class BipartiteMatching:



	def __init__(self, n, m):

		self.n = n

		self.m = m

		# ペアとして有りうる相手を格納する

		self.E = [[] * (n+m+2) for i in range(n+m+2)]

		# 決まったペアを格納する

		self.match = [0] * (n+m+2)

		# 距離(付け替え候補を決める時の深さみたいなものが入ってる)

		self.dist = [0] * (n+m+2)

	

	def bfs(self):

		que = deque()

		for i in range(1, self.n+1):

			# マッチングの決まっていないノードをキューに詰める

			if not self.match[i]:

				self.dist[i] = 0

				que.append(i)

			else:

				self.dist[i] = float('inf')

		self.dist[0] = float('inf')

		while len(que) != 0:

			u = que.popleft()

			if u != 0:

				for v in self.E[u]:

					if self.dist[self.match[v]] == float('inf'):

						self.dist[self.match[v]] = self.dist[u] + 1

						# 付け替えの候補になりうるノードがここで追加されていく

						que.append(self.match[v])

		# フローを流せるエッジが存在しなければ、dist[0]がINFのまま(Falseを返して終了)

		return self.dist[0] != float('inf')



	def dfs(self, u):

		if u != 0:

			for v in self.E[u]:

				if self.dist[self.match[v]] == self.dist[u] + 1:

					if self.dfs(self.match[v]):

						# ペア確定(あとで変わることもある)

						self.match[v] = u

						self.match[u] = v

						return True

			# 今回決められなかったノード

			self.dist[u] = float('inf')

			return False

		return True

	

	def add(self, a, b):

		b += self.n

		self.E[a+1].append(b+1)

		self.E[b+1].append(a+1)



	def whois(self, x):

		return self.match[x+1]-1



	def solve(self):

		for i in range(self.n+self.m+1):

			self.match[i] = 0

		res = 0

		while self.bfs():

			for i in range(1, self.n+1):

				# 前から順に繋げる所は繋いでいって、

				# もっといいのがあれば後から付け替える

				if not self.match[i] and self.dfs(i):

					res += 1

		return res



N = int(eval(input()))

aN, bN, cN, dN = [0] * N, [0] * N, [0] * N, [0] * N

# 赤い点

for i in range(N):

	aN[i], bN[i] = list(map(int, input().split()))

# 青い点

for i in range(N):

	cN[i], dN[i] = list(map(int, input().split()))



# (赤い点の数, 青い点の数)

bm = BipartiteMatching(N, N)

for i in range(N):

	for j in range(N):

		if aN[i] < cN[j] and bN[i] < dN[j]:

			# ペア候補として適切な組を追加していく(0-indexed)

			bm.add(i, j)

print((bm.solve()))

# -*- coding: utf-8 -*-



"""

参考：https://ikatakos.com/pot/programming_algorithm/graph_theory/bipartite_matching

・二部最大マッチング

"""



class BipartiteMatching:

    """

    XとYの二部グラフの最大マッチング X={0,1,2,...|X|-1} Y={0,1,2,...,|Y|-1}

    edges[x]: xとつながるYの頂点のset

    match1[x]: xとマッチングされたYの頂点

    match2[y]: yとマッチングされたXの頂点

    """



    def __init__(self, n, m):

        self.n = n

        self.m = m

        self.edges = [set() for _ in range(n)]

        self.match1 = [-1] * n

        self.match2 = [-1] * m

 

    def dfs(self, v, visited):

        """

        :param v: X側の未マッチングの頂点の1つ

        :param visited: 空のsetを渡す（外部からの呼び出し時）

        :return: 増大路が見つかればTrue

        """

        for u in self.edges[v]:

            if u in visited:

                continue

            visited.add(u)

            if self.match2[u] == -1 or self.dfs(self.match2[u], visited):

                self.match2[u] = v

                self.match1[v] = u

                return True

        return False

    

    def add(self, a, b):

        self.edges[a].add(b)



    def whois1(self, a):

        """ :param: グループ1の頂点 :return: ペアになるグループ2の頂点 """

        return self.match1[a]



    def whois2(self, a):

        """ :param: グループ2の頂点 :return: ペアになるグループ1の頂点 """

        return self.match2[a]



    def solve(self):

        # 増大路発見に成功したらTrue(=1)。合計することでマッチング数となる

        return sum(self.dfs(i, set()) for i in range(self.n))





N = int(eval(input()))

aN, bN, cN, dN = [0] * N, [0] * N, [0] * N, [0] * N

# 赤い点

for i in range(N):

	aN[i], bN[i] = list(map(int, input().split()))

# 青い点

for i in range(N):

	cN[i], dN[i] = list(map(int, input().split()))



# (赤い点の数, 青い点の数)

bm = BipartiteMatching(N, N)

for i in range(N):

	for j in range(N):

		if aN[i] < cN[j] and bN[i] < dN[j]:

			# ペア候補として適切な組を追加していく(0-indexed)

			bm.add(i, j)

print((bm.solve()))

# -*- coding: utf-8 -*-
"""
参考：https://www.hamayanhamayan.com/entry/2018/03/18/085108
　　　http://vartkw.hatenablog.com/entry/2016/12/02/002703
　　　https://ikatakos.com/pot/programming_algorithm/graph_theory/maximum_flow
・二部最大マッチング
・最大流アルゴリズム(Dinic法)
・まだ理解不十分な点はあると思うけど、初めて見た時よりは見慣れた。
"""
from collections import deque


class BipartiteMatching:
    def __init__(self, n, m):
        self.n = n
        self.m = m
        # ペアとして有りうる相手を格納する
        self.E = [[] * (n + m + 2) for i in range(n + m + 2)]
        # 決まったペアを格納する
        self.match = [0] * (n + m + 2)
        # 距離(付け替え候補を決める時の深さみたいなものが入ってる)
        self.dist = [0] * (n + m + 2)

    def bfs(self):
        que = deque()
        for i in range(1, self.n + 1):
            # マッチングの決まっていないノードをキューに詰める
            if not self.match[i]:
                self.dist[i] = 0
                que.append(i)
            else:
                self.dist[i] = float("inf")
        self.dist[0] = float("inf")
        while len(que) != 0:
            u = que.popleft()
            if u != 0:
                for v in self.E[u]:
                    if self.dist[self.match[v]] == float("inf"):
                        self.dist[self.match[v]] = self.dist[u] + 1
                        # 付け替えの候補になりうるノードがここで追加されていく
                        que.append(self.match[v])
        # フローを流せるエッジが存在しなければ、dist[0]がINFのまま(Falseを返して終了)
        return self.dist[0] != float("inf")

    def dfs(self, u):
        if u != 0:
            for v in self.E[u]:
                if self.dist[self.match[v]] == self.dist[u] + 1:
                    if self.dfs(self.match[v]):
                        # ペア確定(あとで変わることもある)
                        self.match[v] = u
                        self.match[u] = v
                        return True
            # 今回決められなかったノード
            self.dist[u] = float("inf")
            return False
        return True

    def add(self, a, b):
        b += self.n
        self.E[a + 1].append(b + 1)
        self.E[b + 1].append(a + 1)

    def whois(self, x):
        return self.match[x + 1] - 1

    def solve(self):
        for i in range(self.n + self.m + 1):
            self.match[i] = 0
        res = 0
        while self.bfs():
            for i in range(1, self.n + 1):
                # 前から順に繋げる所は繋いでいって、
                # もっといいのがあれば後から付け替える
                if not self.match[i] and self.dfs(i):
                    res += 1
        return res


N = int(eval(input()))
aN, bN, cN, dN = [0] * N, [0] * N, [0] * N, [0] * N
# 赤い点
for i in range(N):
    aN[i], bN[i] = list(map(int, input().split()))
# 青い点
for i in range(N):
    cN[i], dN[i] = list(map(int, input().split()))
# (赤い点の数, 青い点の数)
bm = BipartiteMatching(N, N)
for i in range(N):
    for j in range(N):
        if aN[i] < cN[j] and bN[i] < dN[j]:
            # ペア候補として適切な組を追加していく(0-indexed)
            bm.add(i, j)
print((bm.solve()))

# -*- coding: utf-8 -*-
"""
参考：https://ikatakos.com/pot/programming_algorithm/graph_theory/bipartite_matching
・二部最大マッチング
"""


class BipartiteMatching:
    """
    XとYの二部グラフの最大マッチング X={0,1,2,...|X|-1} Y={0,1,2,...,|Y|-1}
    edges[x]: xとつながるYの頂点のset
    match1[x]: xとマッチングされたYの頂点
    match2[y]: yとマッチングされたXの頂点
    """

    def __init__(self, n, m):
        self.n = n
        self.m = m
        self.edges = [set() for _ in range(n)]
        self.match1 = [-1] * n
        self.match2 = [-1] * m

    def dfs(self, v, visited):
        """
        :param v: X側の未マッチングの頂点の1つ
        :param visited: 空のsetを渡す（外部からの呼び出し時）
        :return: 増大路が見つかればTrue
        """
        for u in self.edges[v]:
            if u in visited:
                continue
            visited.add(u)
            if self.match2[u] == -1 or self.dfs(self.match2[u], visited):
                self.match2[u] = v
                self.match1[v] = u
                return True
        return False

    def add(self, a, b):
        self.edges[a].add(b)

    def whois1(self, a):
        """:param: グループ1の頂点 :return: ペアになるグループ2の頂点"""
        return self.match1[a]

    def whois2(self, a):
        """:param: グループ2の頂点 :return: ペアになるグループ1の頂点"""
        return self.match2[a]

    def solve(self):
        # 増大路発見に成功したらTrue(=1)。合計することでマッチング数となる
        return sum(self.dfs(i, set()) for i in range(self.n))


N = int(eval(input()))
aN, bN, cN, dN = [0] * N, [0] * N, [0] * N, [0] * N
# 赤い点
for i in range(N):
    aN[i], bN[i] = list(map(int, input().split()))
# 青い点
for i in range(N):
    cN[i], dN[i] = list(map(int, input().split()))
# (赤い点の数, 青い点の数)
bm = BipartiteMatching(N, N)
for i in range(N):
    for j in range(N):
        if aN[i] < cN[j] and bN[i] < dN[j]:
            # ペア候補として適切な組を追加していく(0-indexed)
            bm.add(i, j)
print((bm.solve()))

-参考：https://www.hamayanhamayan.com/entry/2018/03/18/085108 -　　　http://vartkw.hatenablog.com/entry/2016/12/02/002703 -　　　https://ikatakos.com/pot/programming_algorithm/graph_theory/maximum_flow +参考：https://ikatakos.com/pot/programming_algorithm/graph_theory/bipartite_matching -・最大流アルゴリズム(Dinic法) -・まだ理解不十分な点はあると思うけど、初めて見た時よりは見慣れた。 -from collections import deque +    """ +    XとYの二部グラフの最大マッチング X={0,1,2,...|X|-1} Y={0,1,2,...,|Y|-1} +    edges[x]: xとつながるYの頂点のset +    match1[x]: xとマッチングされたYの頂点 +    match2[y]: yとマッチングされたXの頂点 +    """ + -        # ペアとして有りうる相手を格納する -        self.E = [[] * (n + m + 2) for i in range(n + m + 2)] -        # 決まったペアを格納する -        self.match = [0] * (n + m + 2) -        # 距離(付け替え候補を決める時の深さみたいなものが入ってる) -        self.dist = [0] * (n + m + 2) +        self.edges = [set() for _ in range(n)] +        self.match1 = [-1] * n +        self.match2 = [-1] * m -    def bfs(self): -        que = deque() -        for i in range(1, self.n + 1): -            # マッチングの決まっていないノードをキューに詰める -            if not self.match[i]: -                self.dist[i] = 0 -                que.append(i) -            else: -                self.dist[i] = float("inf") -        self.dist[0] = float("inf") -        while len(que) != 0: -            u = que.popleft() -            if u != 0: -                for v in self.E[u]: -                    if self.dist[self.match[v]] == float("inf"): -                        self.dist[self.match[v]] = self.dist[u] + 1 -                        # 付け替えの候補になりうるノードがここで追加されていく -                        que.append(self.match[v]) -        # フローを流せるエッジが存在しなければ、dist[0]がINFのまま(Falseを返して終了) -        return self.dist[0] != float("inf") - -    def dfs(self, u): -        if u != 0: -            for v in self.E[u]: -                if self.dist[self.match[v]] == self.dist[u] + 1: -                    if self.dfs(self.match[v]): -                        # ペア確定(あとで変わることもある) -                        self.match[v] = u -                        self.match[u] = v -                        return True -            # 今回決められなかったノード -            self.dist[u] = float("inf") -            return False -        return True +    def dfs(self, v, visited): +        """ +        :param v: X側の未マッチングの頂点の1つ +        :param visited: 空のsetを渡す（外部からの呼び出し時） +        :return: 増大路が見つかればTrue +        """ +        for u in self.edges[v]: +            if u in visited: +                continue +            visited.add(u) +            if self.match2[u] == -1 or self.dfs(self.match2[u], visited): +                self.match2[u] = v +                self.match1[v] = u +                return True +        return False -        b += self.n -        self.E[a + 1].append(b + 1) -        self.E[b + 1].append(a + 1) +        self.edges[a].add(b) -    def whois(self, x): -        return self.match[x + 1] - 1 +    def whois1(self, a): +        """:param: グループ1の頂点 :return: ペアになるグループ2の頂点""" +        return self.match1[a] + +    def whois2(self, a): +        """:param: グループ2の頂点 :return: ペアになるグループ1の頂点""" +        return self.match2[a] -        for i in range(self.n + self.m + 1): -            self.match[i] = 0 -        res = 0 -        while self.bfs(): -            for i in range(1, self.n + 1): -                # 前から順に繋げる所は繋いでいって、 -                # もっといいのがあれば後から付け替える -                if not self.match[i] and self.dfs(i): -                    res += 1 -        return res +        # 増大路発見に成功したらTrue(=1)。合計することでマッチング数となる +        return sum(self.dfs(i, set()) for i in range(self.n))