from collections import deque



N = int(eval(input()))

R = [list(map(int,input().split())) for _ in range(N)]

B = [list(map(int,input().split())) for _ in range(N)]



graph = [[] for _ in range(2*N+2)] #残余グラフを構成　0を始点，1を終点とする



for i in range(N):

    forward = [2+i,1,None] #[行き先，流量，逆辺の情報]

    forward[2] = backward = [0,0,forward]

    graph[0].append(forward)

    graph[2+i].append(backward)



for i in range(N):

    forward = [1,1,None]

    forward[2] = backward = [2+N+i,0,forward]

    graph[2+N+i].append(forward)

    graph[1].append(backward)



for i in range(N):

    for j in range(N):

        if R[i][0]<B[j][0] and R[i][1]<B[j][1]:

            forward = [2+N+j,1,None]

            forward[2] = backward = [2+i,0,forward]

            graph[2+i].append(forward)

            graph[2+N+j].append(backward)



flow = 0

while True:



    queue = deque([0])

    level = [None for _ in range(2*N+2)]

    level[0] = 0



    while queue:

        node = queue.popleft()

        for adj,adjcap,_ in graph[node]:

            if adjcap>0 and level[adj] is None:

                level[adj] = level[node]+1

                queue.append(adj)



    if level[1] is None:

        break



    stack = [0]

    visited = [0 for _ in range(2*N+2)]

    visited[0] = 1

    parent = [None for _ in range(2*N+2)]

    parent[0] = 0

    #*it, = map(iter, graph)

    

    while stack:

        node = stack.pop()

        for adj,adjcap,adjrev in graph[node]:

            if not visited[adj] and adjcap>0 and level[node]<level[adj]:

                visited[adj] = 1

                parent[adj] = node

                stack.append(adj)

                

    if visited[1]:

        flow += 1

        node = 1

        prev = parent[node]

        while node != 0:

            for g in graph[prev]:

                adj,adjcap,adjrev = g

                if adj == node:

                    g[1] = 0

                    adjrev[1] = 1

            node = prev

            prev = parent[node]

            

print(flow)
class Node():

    def __init__(self, idx=None):

        self.idx = idx

        self.edge = []

        self.level = None

        self.par = None



class Edge():

    def __init__(self, to, cap, rev=None):

        self.to = to

        self.cap = cap

        self.rev = rev



from collections import deque



class BipartiteMatching():

    def __init__(self, n, m):

        self.n = n

        self.m = m

        self.inf = 10**18

        self.source = Node()

        self.sink = Node()

        self.lt = [Node(i) for i in range(n)]

        self.rt = [Node(i) for i in range(m)]

        for i in range(n):

            edge = Edge(self.lt[i], 1)

            rev = Edge(self.source, 0)

            edge.rev, rev.rev = rev, edge

            self.source.edge.append(edge)

            self.lt[i].edge.append(rev)

        for i in range(m):

            edge = Edge(self.sink, 1)

            rev = Edge(self.rt[i], 0)

            edge.rev, rev.rev = rev, edge

            self.rt[i].edge.append(edge)

            self.sink.edge.append(rev)



    def add(self, x, y):

        lt = self.lt[x]

        rt = self.rt[y]

        edge = Edge(rt, 1)

        rev = Edge(lt, 0)

        edge.rev, rev.rev = rev, edge

        lt.edge.append(edge)

        rt.edge.append(rev)



    def maximum_matching(self):

        flow = 0

        while True:

            queue = deque([self.source])

            self.source.level = 0

            self.sink.level = None

            for i in range(self.n):

                self.lt[i].level = None

            for i in range(self.m):

                self.rt[i].level = None

            while queue:

                node = queue.popleft()

                for edge in node.edge:

                    to = edge.to

                    if edge.cap and to.level is None:

                        to.level = node.level + 1

                        queue.append(to)

            if self.sink.level is None: break

            stack = [self.source]

            self.source.par = None

            self.sink.par = None

            for i in range(self.n):

                self.lt[i].par = None

            for i in range(self.m):

                self.rt[i].par = None

            while stack:

                node = stack.pop()

                if node is self.sink:

                    break

                for edge in node.edge:

                    to = edge.to

                    if edge.cap and node.level < to.level:

                        to.par = edge.rev

                        stack.append(to)

            node = self.sink

            while node is not self.source:

                node.par.cap = 1

                node.par.rev.cap = 0

                node = node.par.to

            flow += 1

        return flow



N = int(eval(input()))

R = [tuple(map(int, input().split())) for _ in range(N)]

B = [tuple(map(int, input().split())) for _ in range(N)]



bip = BipartiteMatching(N, N)



for i in range(N):

    a, b = R[i]

    for j in range(N):

        c, d = B[j]

        if a < c and b < d:

            bip.add(i, j)



print((bip.maximum_matching()))
from collections import deque

N = int(eval(input()))
R = [list(map(int, input().split())) for _ in range(N)]
B = [list(map(int, input().split())) for _ in range(N)]
graph = [[] for _ in range(2 * N + 2)]  # 残余グラフを構成　0を始点，1を終点とする
for i in range(N):
    forward = [2 + i, 1, None]  # [行き先，流量，逆辺の情報]
    forward[2] = backward = [0, 0, forward]
    graph[0].append(forward)
    graph[2 + i].append(backward)
for i in range(N):
    forward = [1, 1, None]
    forward[2] = backward = [2 + N + i, 0, forward]
    graph[2 + N + i].append(forward)
    graph[1].append(backward)
for i in range(N):
    for j in range(N):
        if R[i][0] < B[j][0] and R[i][1] < B[j][1]:
            forward = [2 + N + j, 1, None]
            forward[2] = backward = [2 + i, 0, forward]
            graph[2 + i].append(forward)
            graph[2 + N + j].append(backward)
flow = 0
while True:
    queue = deque([0])
    level = [None for _ in range(2 * N + 2)]
    level[0] = 0
    while queue:
        node = queue.popleft()
        for adj, adjcap, _ in graph[node]:
            if adjcap > 0 and level[adj] is None:
                level[adj] = level[node] + 1
                queue.append(adj)
    if level[1] is None:
        break
    stack = [0]
    visited = [0 for _ in range(2 * N + 2)]
    visited[0] = 1
    parent = [None for _ in range(2 * N + 2)]
    parent[0] = 0
    # *it, = map(iter, graph)
    while stack:
        node = stack.pop()
        for adj, adjcap, adjrev in graph[node]:
            if not visited[adj] and adjcap > 0 and level[node] < level[adj]:
                visited[adj] = 1
                parent[adj] = node
                stack.append(adj)
    if visited[1]:
        flow += 1
        node = 1
        prev = parent[node]
        while node != 0:
            for g in graph[prev]:
                adj, adjcap, adjrev = g
                if adj == node:
                    g[1] = 0
                    adjrev[1] = 1
            node = prev
            prev = parent[node]
print(flow)

class Node:
    def __init__(self, idx=None):
        self.idx = idx
        self.edge = []
        self.level = None
        self.par = None


class Edge:
    def __init__(self, to, cap, rev=None):
        self.to = to
        self.cap = cap
        self.rev = rev


from collections import deque


class BipartiteMatching:
    def __init__(self, n, m):
        self.n = n
        self.m = m
        self.inf = 10**18
        self.source = Node()
        self.sink = Node()
        self.lt = [Node(i) for i in range(n)]
        self.rt = [Node(i) for i in range(m)]
        for i in range(n):
            edge = Edge(self.lt[i], 1)
            rev = Edge(self.source, 0)
            edge.rev, rev.rev = rev, edge
            self.source.edge.append(edge)
            self.lt[i].edge.append(rev)
        for i in range(m):
            edge = Edge(self.sink, 1)
            rev = Edge(self.rt[i], 0)
            edge.rev, rev.rev = rev, edge
            self.rt[i].edge.append(edge)
            self.sink.edge.append(rev)

    def add(self, x, y):
        lt = self.lt[x]
        rt = self.rt[y]
        edge = Edge(rt, 1)
        rev = Edge(lt, 0)
        edge.rev, rev.rev = rev, edge
        lt.edge.append(edge)
        rt.edge.append(rev)

    def maximum_matching(self):
        flow = 0
        while True:
            queue = deque([self.source])
            self.source.level = 0
            self.sink.level = None
            for i in range(self.n):
                self.lt[i].level = None
            for i in range(self.m):
                self.rt[i].level = None
            while queue:
                node = queue.popleft()
                for edge in node.edge:
                    to = edge.to
                    if edge.cap and to.level is None:
                        to.level = node.level + 1
                        queue.append(to)
            if self.sink.level is None:
                break
            stack = [self.source]
            self.source.par = None
            self.sink.par = None
            for i in range(self.n):
                self.lt[i].par = None
            for i in range(self.m):
                self.rt[i].par = None
            while stack:
                node = stack.pop()
                if node is self.sink:
                    break
                for edge in node.edge:
                    to = edge.to
                    if edge.cap and node.level < to.level:
                        to.par = edge.rev
                        stack.append(to)
            node = self.sink
            while node is not self.source:
                node.par.cap = 1
                node.par.rev.cap = 0
                node = node.par.to
            flow += 1
        return flow


N = int(eval(input()))
R = [tuple(map(int, input().split())) for _ in range(N)]
B = [tuple(map(int, input().split())) for _ in range(N)]
bip = BipartiteMatching(N, N)
for i in range(N):
    a, b = R[i]
    for j in range(N):
        c, d = B[j]
        if a < c and b < d:
            bip.add(i, j)
print((bip.maximum_matching()))

+class Node: +    def __init__(self, idx=None): +        self.idx = idx +        self.edge = [] +        self.level = None +        self.par = None + + +class Edge: +    def __init__(self, to, cap, rev=None): +        self.to = to +        self.cap = cap +        self.rev = rev + + + +class BipartiteMatching: +    def __init__(self, n, m): +        self.n = n +        self.m = m +        self.inf = 10**18 +        self.source = Node() +        self.sink = Node() +        self.lt = [Node(i) for i in range(n)] +        self.rt = [Node(i) for i in range(m)] +        for i in range(n): +            edge = Edge(self.lt[i], 1) +            rev = Edge(self.source, 0) +            edge.rev, rev.rev = rev, edge +            self.source.edge.append(edge) +            self.lt[i].edge.append(rev) +        for i in range(m): +            edge = Edge(self.sink, 1) +            rev = Edge(self.rt[i], 0) +            edge.rev, rev.rev = rev, edge +            self.rt[i].edge.append(edge) +            self.sink.edge.append(rev) + +    def add(self, x, y): +        lt = self.lt[x] +        rt = self.rt[y] +        edge = Edge(rt, 1) +        rev = Edge(lt, 0) +        edge.rev, rev.rev = rev, edge +        lt.edge.append(edge) +        rt.edge.append(rev) + +    def maximum_matching(self): +        flow = 0 +        while True: +            queue = deque([self.source]) +            self.source.level = 0 +            self.sink.level = None +            for i in range(self.n): +                self.lt[i].level = None +            for i in range(self.m): +                self.rt[i].level = None +            while queue: +                node = queue.popleft() +                for edge in node.edge: +                    to = edge.to +                    if edge.cap and to.level is None: +                        to.level = node.level + 1 +                        queue.append(to) +            if self.sink.level is None: +                break +            stack = [self.source] +            self.source.par = None +            self.sink.par = None +            for i in range(self.n): +                self.lt[i].par = None +            for i in range(self.m): +                self.rt[i].par = None +            while stack: +                node = stack.pop() +                if node is self.sink: +                    break +                for edge in node.edge: +                    to = edge.to +                    if edge.cap and node.level < to.level: +                        to.par = edge.rev +                        stack.append(to) +            node = self.sink +            while node is not self.source: +                node.par.cap = 1 +                node.par.rev.cap = 0 +                node = node.par.to +            flow += 1 +        return flow + + -R = [list(map(int, input().split())) for _ in range(N)] -B = [list(map(int, input().split())) for _ in range(N)] -graph = [[] for _ in range(2 * N + 2)]  # 残余グラフを構成　0を始点，1を終点とする +R = [tuple(map(int, input().split())) for _ in range(N)] +B = [tuple(map(int, input().split())) for _ in range(N)] +bip = BipartiteMatching(N, N) -    forward = [2 + i, 1, None]  # [行き先，流量，逆辺の情報] -    forward[2] = backward = [0, 0, forward] -    graph[0].append(forward) -    graph[2 + i].append(backward) -for i in range(N): -    forward = [1, 1, None] -    forward[2] = backward = [2 + N + i, 0, forward] -    graph[2 + N + i].append(forward) -    graph[1].append(backward) -for i in range(N): +    a, b = R[i] -        if R[i][0] < B[j][0] and R[i][1] < B[j][1]: -            forward = [2 + N + j, 1, None] -            forward[2] = backward = [2 + i, 0, forward] -            graph[2 + i].append(forward) -            graph[2 + N + j].append(backward) -flow = 0 -while True: -    queue = deque([0]) -    level = [None for _ in range(2 * N + 2)] -    level[0] = 0 -    while queue: -        node = queue.popleft() -        for adj, adjcap, _ in graph[node]: -            if adjcap > 0 and level[adj] is None: -                level[adj] = level[node] + 1 -                queue.append(adj) -    if level[1] is None: -        break -    stack = [0] -    visited = [0 for _ in range(2 * N + 2)] -    visited[0] = 1 -    parent = [None for _ in range(2 * N + 2)] -    parent[0] = 0 -    # *it, = map(iter, graph) -    while stack: -        node = stack.pop() -        for adj, adjcap, adjrev in graph[node]: -            if not visited[adj] and adjcap > 0 and level[node] < level[adj]: -                visited[adj] = 1 -                parent[adj] = node -                stack.append(adj) -    if visited[1]: -        flow += 1 -        node = 1 -        prev = parent[node] -        while node != 0: -            for g in graph[prev]: -                adj, adjcap, adjrev = g -                if adj == node: -                    g[1] = 0 -                    adjrev[1] = 1 -            node = prev -            prev = parent[node] -print(flow) +        c, d = B[j] +        if a < c and b < d: +            bip.add(i, j) +print((bip.maximum_matching()))