Problem:
 Score : 400 points    Problem Statement On a two-dimensional plane, there are N red points and N blue points.
The coordinates of the i -th red point are (a_i, b_i) , and the coordinates of the i -th blue point are (c_i, d_i) .  A red point and a blue point can form a friendly pair when, the x -coordinate of the red point is smaller than that of the blue point, and the y -coordinate of the red point is also smaller than that of the blue point.  At most how many friendly pairs can you form? Note that a point cannot belong to multiple pairs.      Constraints  All input values are integers.  1 \leq N \leq 100  0 \leq a_i, b_i, c_i, d_i < 2N  a_1, a_2, ..., a_N, c_1, c_2, ..., c_N are all different.  b_1, b_2, ..., b_N, d_1, d_2, ..., d_N are all different.         Input Input is given from Standard Input in the following format:  N  a_1  b_1  a_2  b_2  :  a_N  b_N  c_1  d_1  c_2  d_2  :  c_N  d_N       Output Print the maximum number of friendly pairs.        Sample Input 1 3
2 0
3 1
1 3
4 2
0 4
5 5      Sample Output 1 2  For example, you can pair (2, 0) and (4, 2) , then (3, 1) and (5, 5) .       Sample Input 2 3
0 0
1 1
5 2
2 3
3 4
4 5      Sample Output 2 2  For example, you can pair (0, 0) and (2, 3) , then (1, 1) and (3, 4) .       Sample Input 3 2
2 2
3 3
0 0
1 1      Sample Output 3 0  It is possible that no pair can be formed.       Sample Input 4 5
0 0
7 3
2 2
4 8
1 6
8 5
6 9
5 4
9 1
3 7      Sample Output 4 5       Sample Input 5 5
0 0
1 1
5 5
6 6
7 7
2 2
3 3
4 4
8 8
9 9      Sample Output 5 4

Solution (Python):
class Bipartite_Matching():
    
    def __init__(self, n):
        self.match = [-1]*n
        self.used = [0]*n
        self.n = n
        self.edges = [[] for i in range(n)]

    
    def add_edge(self, u, v):
        self.edges[u].append(v)

    
    def dfs(self, v):
        self.used[v] = 1
        for u in self.edges[v]:
            w = self.match[u]
            if w < 0 or (not self.used[w] and self.dfs(w)):
                self.match[v] = u
                self.match[u] = v
                return True
        return False

    
    def bipartite_matching(self):
        ret = 0
        for v in range(self.n):
            if self.match[v] < 0:
                self.used = [0]*self.n
                if self.dfs(v):
                    ret += 1
        return ret


n = int(input())
BP = Bipartite_Matching(2*n)
red = [None]*n
for i in range(n):
    a, b = map(int, input().split())
    red[i] = (a, b)
blue = [None]*n
for i in range(n):
    c, d = map(int, input().split())
    blue[i] = (c, d)


for i in range(n):
    c, d = blue[i]
    for j in range(n):
        a, b = red[j]
        if a < c and b < d:
            BP.add_edge(n+i, j)
            BP.add_edge(j, n+i)
ans = BP.bipartite_matching()
print(ans)

Solution (Python):
def bipertite_matching(N, edges):
    def dfs(v):
        used[v] = True
        for u in edges[v]:
            w = match[u]
            if w < 0 or (used[w] == False and dfs(w)):
                match[v] = u
                match[u] = v
                return True
        return False
    match = [-1 for _ in range(N)]
    ret = 0
    for v in range(N):
        if match[v] < 0:
            used = [False for _ in range(N)]
            if dfs(v):
                ret += 1
    return ret

N = int(input())
a, b = [None] * N, [None] * N
for i in range(N):
    a[i], b[i] = map(int, input().split())
c, d = [None] * N, [None] * N
for i in range(N):
    c[i], d[i] = map(int, input().split())
es = [[] for i in range(2 * N)]
for i in range(N):
    for j in range(N):
        if a[i] < c[j] and b[i] < d[j]:
            es[i].append(N+j)
            es[N+j].append(i)
print(bipertite_matching(2*N, es))

Solution (Python):
N = int(input())
 
reds = []
for _ in range(N):
    reds.append(tuple(map(int, input().split())))
    
blues = []
for _ in range(N):
    blues.append(tuple(map(int, input().split())))

reds.sort()
blues.sort()
 
ans = 0
for blue in blues:
    c, d = blue
 
    
    targets = [red for red in reds if red[0] < c and red[1] < d]
    targets.sort(key=lambda x:x[1])
 
    
    if targets:
        target = targets.pop()
        reds.remove(target)
        ans += 1
print(ans)

Solution (Python):
N = int(input())

reds = []
for _ in range(N):
    reds.append(tuple(map(int, input().split())))
    
blues = []
for _ in range(N):
    blues.append(tuple(map(int, input().split())))

reds.sort()
blues.sort()

ans = 0
for blue in blues:
    c, d = blue

    
    targets = [red for red in reds if red[0] < c and red[1] < d]
    targets.sort(key=lambda x:x[1])

    
    if targets:
        target = targets.pop()
        reds.remove(target)
        ans += 1

print(ans)

Solution (Python):
N = int(input())
R = [list(map(int, input().split())) for _ in range(N)]
B = [list(map(int, input().split())) for _ in range(N)]
B.sort()

R.sort(key=lambda x: -x[1])

cnt = 0
for b in B:
    
    bx = b[0]; by = b[1]
    
    for ir, r in enumerate(R):
        rx = r[0]; ry = r[1]
        
        if rx < bx and ry < by:
            R.pop(ir)
            cnt += 1
            break
print(cnt)

Solution (Python):
N = int(input())
R=[list(map(int,input().split())) for i in range(N) ]
B=[list(map(int,input().split()))  for i in range(N) ]
R.sort(key=lambda x:x[1],reverse=1)
B.sort()
ans=0
for b in B:
    for r in R:
        if b[1]>r[1] and b[0]>r[0]:
            ans+=1
            R.remove(r)
            break
print(ans)

Solution (Python):
if __name__ == '__main__':
    N = int(input())
    ab_list = [list(map(int, input().split())) for i in range(N)]
    cd_list = [list(map(int, input().split())) for i in range(N)]

    ab_list = sorted(ab_list, key=lambda x : x[1], reverse=True)
    cd_list = sorted(cd_list, key=lambda x : x[0])

    answer = 0
    for b in cd_list:
        for r in ab_list:
            if b[0]>r[0] and b[1]>r[1]:
                answer += 1
                ab_list.remove(r)
                break
    print(answer)

Solution (Python):
n=int(input())
ab=[list(map(int,input().split())) for _ in range(n)]
cd=[list(map(int,input().split())) for _ in range(n)]
ab.sort(key=lambda x:x[1], reverse=True)
cd.sort()
ans=0
for i in range(n):
    for a in ab:
        if a[0]<cd[i][0] and a[1]<cd[i][1]:
            ab.remove(a)
            ans+=1
            break
print(ans)

Solution (Python):
import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from heapq import heappop, heappush, heapify, heappushpop
from itertools import permutations, combinations, product, accumulate
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits

def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
MOD = 10 ** 9 + 7

N = INT()
ab = [LIST() for _ in range(N)]
cd = [LIST() for _ in range(N)]

ab.sort(key=lambda x:(-x[1], -x[0]))
cd.sort(key=lambda x:(x[0], x[1]))

ans = 0
for c, d in cd:  
	for i in range(len(ab)):  
		if c > ab[i][0] and d > ab[i][1]:  
			
			ab.pop(i)
			ans += 1
			break
print(ans)

Solution (Python):
n=int(input())

a=[]
for i in range(n):
    x,y=map(int,input().split())
    a.append([x,y])

b=[]
for i in range(n):
    x,y=map(int,input().split())
    b.append([x,y])


a2=sorted(a, key=lambda x: x[1])
b2=sorted(b, key=lambda x: x[0])

ans=0
for i in range(n):
    for j in range(n):
        if b2[i][0]>a2[n-1-j][0] and b2[i][1]>a2[n-1-j][1]:
            ans+=1
            a2[n-1-j][0]=3*n
            break

print(ans)

Solution (Python):

from collections import deque
class Dinic:
    def __init__(self, N):
        self.N = N
        self.G = [[] for i in range(N)]

    def add_edge(self, fr, to, cap):
        forward = [to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)

    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)

    def bfs(self, s, t):
        self.level = level = [None]*self.N
        deq = deque([s])
        level[s] = 0
        G = self.G
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        return level[t] is not None

    def dfs(self, v, t, f):
        if v == t:
            return f
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0

    def flow(self, s, t):
        flow = 0
        INF = 10**9 + 7
        G = self.G
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow

N = int(input())
ab = [ list(map(int,input().split())) for i in range(N)]
cd = [ list(map(int,input().split())) for i in range(N)]

D = Dinic(N*2+2)

for i in range(N):
    for j in range(N):
        if ab[i][0] < cd[j][0] and ab[i][1] < cd[j][1]:
            D.add_edge(i,j+N,1)

for i in range(N):
    D.add_edge(N*2,i,1)
for i in range(N):
    D.add_edge(i+N,N*2+1,1)

print(D.flow(N*2,N*2+1))

Solution (Python):
n=int(input())
point=[]
for i in range(n):
    a,b=map(int,input().split())
    point.append((b,a,0))
for i in range(n):
    a,b=map(int,input().split())
    point.append((b,a,1))
point.sort()
stock=[]
ans=0
for p in point:
    if p[2]==0:
        stock.append(p)
    else:
        if stock==[]:
            pass
        else:
            I=-1
            D=300
            for i in range(len(stock)):
                if stock[i][1]<p[1]:
                    if p[1]-stock[i][1]<D:
                        D=p[1]-stock[i][1]
                        I=i
            if I==-1:
                pass
            else:
                ans=ans+1
                del stock[I]
print(ans)

Solution (Python):
N=int(input())
ab=sorted([list(map(int,input().split())) for _ in [0]*N],key=lambda x:x[1],reverse=True)
cd=sorted([list(map(int,input().split())) for _ in [0]*N],key=lambda x:x[0])
cnt=0
for i in range(N):
    for a in ab:
        if a[0]<cd[i][0] and a[1]<cd[i][1]:
            ab.remove(a)
            cnt+=1
            break
print(cnt)

Solution (Python):
N=int(input())
ab=[list(map(int,input().split())) for _ in range(N)]
cd=[list(map(int,input().split())) for _ in range(N)]

ab=[x[0]+x[1]*1j for x in ab]
cd=[x[0]+x[1]*1j for x in cd]

def comp(a,b):
	if a.real<b.real and a.imag<b.imag:
		return True
	else:
		return False

abd=dict()
cdd=dict()

for i in range(len(ab)):
	temp=[]
	for j in range(len(cd)):
		if comp(ab[i],cd[j]):
			temp.append(cd[j])
	if temp!=[]:
		abd[ab[i]]=temp
	
for i in range(len(cd)):
	temp=[]
	for j in range(len(ab)):
		if comp(ab[j],cd[i]):
			temp.append(ab[j])
	if temp!=[]:
		cdd[cd[i]]=temp
	
ans=0
while(len(abd.keys())+len(cdd.keys())):
	m=10**5
	
	for i in abd.keys():
		for j in abd[i]:
			cnt=len(abd[i])+len(cdd[j])
			if cnt<m:
				m=cnt
				abm=i
				cdm=j
	
	cdl=abd[abm]
	abl=cdd[cdm]
	
	for i in abl:
		abd[i].remove(cdm)
	for i in cdl:
		cdd[i].remove(abm)
	
	del abd[abm]
	del cdd[cdm]
	
	abk=[i for i in abd.keys()]
	cdk=[i for i in cdd.keys()]
	
	for i in abk:
		if abd[i]==[]:
			del abd[i]
	for i in cdk:
		if cdd[i]==[]:
			del cdd[i]
	ans+=1
print(ans)

Solution (Python):
n = int(input())
red = []
blue = []
for _ in range(n):
    a, b = map(int, input().split())
    red.append([a, b])
for _ in range(n):
    c, d = map(int, input().split())
    blue.append([c, d])
blue.sort()
red.sort(key=lambda x: x[1], reverse=True)
ans = 0
for b in blue:
    for i, r in enumerate(red):
        if (r[0] < b[0]) & (r[1] < b[1]):
            ans += 1
            red.pop(i)
            break
print(ans)

Solution (Python):
nl = lambda: list(map(int, input().split()))
sl = lambda: input().split()
n = lambda: int(input())
s = lambda: input()


import queue
from collections import defaultdict
def max_flow(edges, num_of_vertices, start, goal):
    level = defaultdict(lambda: -1)
    seen = set()

    def bfs(s):
        level[s] = 0
        q = queue.Queue()
        q.put(s)
        while not q.empty():
            v = q.get()
            for nv, cap in edges[v].items():
                if cap > 0 and level[nv] < 0:
                    level[nv] = level[v] + 1
                    q.put(nv)

    def dfs(v, t, f):
        if v == t:
            return f
        for nv, cap in edges[v].items():
            if (v, nv) in seen:
                continue
            seen.add((v, nv))
            if cap > 0 and level[v] < level[nv]:
                d = dfs(nv, t, min(f, cap))
                if d > 0:
                    edges[v][nv] -= d
                    edges[nv][v] += d
                    return d
        return 0

    flow = 0
    while True:
        level.clear()
        bfs(start)
        if level[goal] < 0:
            return flow
        seen.clear()
        while True:
            f = dfs(start, goal, float('inf'))
            if f == 0:
                break
            flow += f
    return flow

N = n()

reds = []
edges = defaultdict(dict)

for i in range(N):
    reds.append(nl())
    edges[0][i+1] = 1
    edges[i+1][0] = 0
blues = []
for i in range(N):
    blues.append(nl())
    edges[N+i+1][2*N+1] = 1
    edges[2*N+1][N+i+1] = 0

for i in range(N):
    for j in range(N):
        rx, ry = reds[i]
        bx, by = blues[j]
        if rx < bx and ry < by:
            edges[i+1][N+j+1] = 1
            edges[N+j+1][i+1] = 0

print(max_flow(edges, 2*N+2, 0, 2*N+1))

Solution (Python):
N = int(input())

red = [list(map(int,input().split())) for i in range(N)]
blue = [list(map(int,input().split())) for i in range(N)]

red = sorted(red, key=lambda x: x[1], reverse=True)
blue = sorted(blue, key=lambda x: x[0], reverse=False)

flg = [0 for i in range(N)]

ans = 0

for i in range(N) :
    c,d = blue[i]
    for j in range(N) :
        if flg[j] :
            continue
        
        a,b = red[j]
        
        if (a < c) and (b < d) :
            ans += 1
            flg[j] = 1
            break

print(ans)

Solution (Python):
N = int(input())
A = [list(map(int, input().split()))+[0] for i in range(N)] + [[2*N+1, -1, 0]]
B = [list(map(int, input().split())) for i in range(N)]
B.sort()


cnt = 0
for a,b in B:
    idx = -1
    for j in range(N):
        c,d,used = A[j]
        if a > c and b > d and used == 0 and A[idx][1] < d:
            idx = j
    if idx != -1:
        A[idx][2] = 1
        cnt += 1
        
print(cnt)

Solution (Python):
from scipy.sparse.csgraph import dijkstra


N = int(input())
NN = N * 2
XY = [[int(x) for x in input().split()] for _ in range(NN)]
graph = [[0] * (NN+2) for _ in range(NN+2)]
start = NN
goal = NN+1

for i,(a,b) in enumerate(XY[:N]):
  for j,(c,d) in enumerate(XY[N:], N):
    if a < c and b < d:
      graph[i][j] = 1

for i in range(N):
  graph[start][i] = 1
for i in range(N,NN):
  graph[i][goal] = 1
  
INF = 10 ** 9

def max_flow(graph):
  dist, pred = dijkstra(graph, indices = start, return_predecessors = True)
  if dist[goal] > INF:
    return 0
  y = goal
  while y != start:
    x = pred[y]
    graph[x][y] -= 1
    graph[y][x] += 1
    y = x
  return 1 + max_flow(graph)

answer = max_flow(graph)
print(answer)

Solution (Python):
n = int(input())
red = [list(map(int, input().split())) for _ in range(n)]
blue = [list(map(int, input().split())) for _ in range(n)]
red.sort(key=lambda x: x[0])
blue.sort(key=lambda x: x[0])

ans = 0
for b in blue:
    tmp_y = -1
    pop_i = None
    flag = False
    for i, r in enumerate(red):
        if r[0] >= b[0]:
            break
        if r[1] < b[1]:
            flag = True
            if r[1] >= tmp_y:
                pop_i = i
                tmp_y = r[1]
    if flag:
        red.pop(pop_i)
        ans += 1
print(ans)

Solution (Python):
n=int(input())
R=[]
B=[]
for i in range(n):
    r=[int(i) for i in input().split()]
    R.append(r)
R.sort(key=lambda x:x[0])
for i in range(n):
    b=[int(i) for i in input().split()]
    B.append(b)
B.sort(key=lambda x:x[0])
ans=0
for b in B:
    stock=[]
    for r in R:
        if r[0]<b[0] and r[1]<b[1]:
            stock.append(r)
    if 0<len(stock):
        stock.sort(key=lambda x:x[1],reverse=True)
        red=stock[0]
        ans+=1
        R.remove(red)


print(ans)

Solution (Python):
N = int(input())

alist = []
blist = []
for _ in range(N):
    a, b = map(int, input().split())
    alist.append((b, a))

for _ in range(N):
    c, d = map(int, input().split())
    blist.append((c, d))

alist.sort(reverse=True)
blist.sort()

ans = 0
for i in range(N):
    for j in range(len(alist)):
        if blist[i][0] > alist[j][1] and blist[i][1] > alist[j][0]:
            ans += 1
            alist = alist[:j] + alist[j+1:]
            break

print(ans)

Solution (Python):

n = int(input())
lst_r = [list(map(int, input().split())) for _ in range(n)]
lst_b = [list(map(int, input().split())) for _ in range(n)]
lst_r.sort(key=lambda x:-x[1])
lst_b.sort()


ans = 0
for b in lst_b:
    for r in lst_r:
        if r[0] < b[0] and r[1] < b[1]:
            ans += 1
            lst_r.remove(r)
            break


print(ans)

Solution (Python):
N=int(input())
R=[list(map(int,input().split())) for i in range(N) ]
B=[list(map(int,input().split()))  for i in range(N) ]
R.sort(key=lambda x:x[1],reverse=1)
B.sort()
ans=0
for b in B:
    for r in R:
        if b[1]>r[1] and b[0]>r[0]:
            ans+=1
            R.remove(r)
            break
print(ans)

Solution (Python):
n = int(input())
red = [[0,0] for _ in range(n)]
blue = [[0,0] for _ in range(n)]

for i in range(n):
    red[i][0], red[i][1] = map(int,input().split())
for i in range(n):
    blue[i][0], blue[i][1] = map(int,input().split())
    
red.sort(key = lambda x:-x[1])
blue.sort(key = lambda x:x[0])

flag = [True] * n

for i in range(n):
    for j in range(n):
        if flag[j] and red[j][0] < blue[i][0] and red[j][1] < blue[i][1]:
            flag[j] = False
            break

ans = 0
for i in range(n):
    if not flag[i]:
        ans += 1

print(ans)

Solution (Python):
N=int(input())
red=[tuple(map(int,input().split())) for _ in range(N)]
blue=[tuple(map(int,input().split())) for _ in range(N)]

blue=sorted(blue, key=lambda x: x[0])

ans=0

for b in blue:
    candi=[i for i in red if i[0]<b[0] and i[1]<b[1]]
    if candi:
        red.remove(sorted(candi, key=lambda x: x[1], reverse=True)[0])
        ans+=1

print(ans)

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

R.sort(key=lambda x: -x[1])
B.sort(key=lambda x: x[0])

idx = 0
ans = 0
for xr, yr in R:
    for xb, yb in B:
        if xr < xb and yr < yb:
            ans += 1
            B.remove([xb, yb])
            break
            
print(ans)

Solution (Python):
N = int(input())
X = [list(map(int, input().split())) for _ in range(N)]
Y = [list(map(int, input().split())) for _ in range(N)]
X.sort(key=lambda x:x[1], reverse=True)
Y.sort()
ans = 0
xf = [0] * N
yf = [0] * N
C = []
i = 0
while i < N:
    if yf[i] == 1:
        i+= 1
        continue
    for j in range(N):
        if xf[j] == 0:
            if Y[i][0] > X[j][0] and Y[i][1] > X[j][1]:
                ans += 1
                xf[j] = 1
                yf[i] = 1
                i = 0
                break

    i += 1
print(ans)

Solution (Python):
import queue

class Dinic():
    def __init__(self, v, inf = 1000000007):
        self.V = v
        self.inf = inf
        self.G = [[] for _ in range(v)]
        self.level = [0 for _ in range(v)]
        self.iter = [0 for _ in range(v)]

    def add_edge(self, from_, to, cap):
        
        self.G[from_].append({'to':to, 'cap':cap, 'rev':len(self.G[to])})
        self.G[to].append({'to':from_, 'cap':0, 'rev':len(self.G[from_])-1})

    
    def bfs(self, s):
        self.level = [-1 for _ in range(self.V)]
        self.level[s] = 0;
        que = queue.Queue()
        que.put(s)
        while not que.empty():
            v = que.get()
            for i in range(len(self.G[v])):
                e = self.G[v][i]
                if e['cap'] > 0 and self.level[e['to']] < 0:
                    self.level[e['to']] = self.level[v] + 1
                    que.put(e['to'])
     
    
    def dfs(self, v, t, f):
        if v == t: return f
        for i in range(self.iter[v], len(self.G[v])):
            self.iter[v] = i
            e = self.G[v][i]
            if e['cap'] > 0 and self.level[v] < self.level[e['to']]:
                d = self.dfs(e['to'], t, min(f, e['cap']))
                if d > 0:
                    e['cap'] -= d
                    self.G[e['to']][e['rev']]['cap'] += d
                    return d
        return 0

    def max_flow(self, s, t):
        flow = 0
        while True:
            self.bfs(s)
            
            if self.level[t] < 0 : return flow
            self.iter = [0 for _ in range(self.V)]
            f = self.dfs(s, t, self.inf)
            while f > 0:
                flow += f
                f = self.dfs(s,t, self.inf)


N = int(input())
AB = [list(map(int,input().split())) for i in range(N)]
CD = [list(map(int,input().split())) for i in range(N)]

MF = Dinic(2*N+2) 


for i in range(N):
  for j in range(N):
    if AB[i][0] < CD[j][0] and AB[i][1] < CD[j][1]:
      MF.add_edge(i, j+N, 1) 
      

for i in range(N):
  MF.add_edge(2*N, i, 1)
  

for j in range(N):
  MF.add_edge(j+N, 2*N+1, 1) 
  
max_flow = MF.max_flow(2*N, 2*N+1)
print(max_flow)

Solution (Python):
N = int(input())

rs, bs = [], []  

for _ in range(N):
    rs.append(list(map(int, input().split())) + [0])

for _ in range(N):
    bs.append(list(map(int, input().split())) + [0])

rs.sort(key=lambda x: x[1])
bs.sort()

npair = 0
ir, ib = 0, 0
while ib < N:
    bx, by, _ = bs[ib]
    ir = N-1
    while ir >= 0:
        rx, ry, paired = rs[ir]
        if not paired and rx < bx and ry < by:
            rs[ir][2] = bs[ib][2] = 1
            npair += 1
            break
        ir -= 1
    ib += 1

print(npair)

Solution (Python):

import sys


def solve(N: int, a: "List[int]", b: "List[int]", c: "List[int]", d: "List[int]"):
    red = sorted([[a[i],b[i]] for i in range(N)], key=lambda x:x[1], reverse=True)
    blue = sorted([[c[i],d[i]] for i in range(N)], key=lambda x:x[0])

    checked = [False] * N
    

    for i in range(N):
        for j in range(N):
            if((red[j][0] < blue[i][0] and red[j][1] < blue[i][1]) and  not checked[j]):
                checked[j] = True
                break

    print(checked.count(True))

        
    return



def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  
    a = [int()] * (N)  
    b = [int()] * (N)  
    for i in range(N):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
    c = [int()] * (N)  
    d = [int()] * (N)  
    for i in range(N):
        c[i] = int(next(tokens))
        d[i] = int(next(tokens))
    solve(N, a, b, c, d)

if __name__ == '__main__':
    main()

Solution (Python):



class Edge(object):

    def __init__(self, src, dst, cap):
        self.src = src
        self.dst = dst
        self.cap = cap
        self.rev = None

    def create_rev(self):
        """
        対応する残余グラフの辺を作成して返す。
        本来の辺と残余グラフの辺は相互に参照を持ち合うため、このメソッド以外から生成しないこと。
        """
        rev = Edge(self.dst, self.src, 0)
        self.rev = rev
        rev.rev = self
        return rev


class FordFulkerson:

    def __init__(self, N):
        self.N = N
        self.G = [list() for _ in range(N)]  

    def add_edge(self, src, dst, cap):
        forward = Edge(src, dst, cap)
        backward = forward.create_rev()
        self.G[src].append(forward)
        self.G[dst].append(backward)

    def flow(self, src, dst):
        max_flow = 0
        while True:
            self.used = [0] * self.N
            flow = self._dfs(src, dst)
            if flow == 0:  
                break
            max_flow += flow
        return max_flow

    def _dfs(self, v, t, f=float('inf')):
        """
        深さ優先でグラフを走査し、目的地に達するパスがあるか検索する。
        パスが存在すればその時の最大流を返し、存在しなければ0を返す。
        最大流量がFである時、高々F回のDFSをすることになるため、 O(F|E|) となる。

        :param v: 始点のインデックス
        :param t: 終点のインデックス
        :param f: 現在の再帰スタックにおける暫定の最大流
        """
        if v == t:
            return f
        used = self.used
        used[v] = 1
        for e in self.G[v]:
            if e.cap and not used[e.dst]:
                d = self._dfs(e.dst, t, min(f, e.cap))
                if d:
                    e.cap -= d
                    e.rev.cap += d
                    return d
        return 0


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





ff = FordFulkerson(2 * N + 2)
for i in range(N):
    r_x, r_y = reds[i]
    r_idx = i + 1
    ff.add_edge(0, r_idx, 1)  
    for j in range(N):
        b_x, b_y = blues[j]
        b_idx = j + N + 1
        if r_x < b_x and r_y < b_y:
            ff.add_edge(r_idx, b_idx, 1)  
for i in range(N + 1, 2 * N + 1):
    ff.add_edge(i, 2 * N + 1, 1)  


print(ff.flow(0, 2 * N + 1))

Solution (Python):
N = int(input())
red = [list(map(int,input().split())) for i in range(N)]
blue = [list(map(int,input().split()))  for i in range(N)]

red = sorted(red, key=lambda x: x[0])
blue = sorted(blue, key=lambda x: x[0])


ans = 0

red_candidate = []
flag = False
for i in blue:
    red_candidate = []
    for j in range(len(red)):
        if i[0] <= red[j][0]:
            break
        else:
            if red[j][1] < i[1]:
                red_candidate.append([red[j][1], j])
                flag = True

    tmp_red_ymax_index = 0
    red_candidate = sorted(red_candidate, key=lambda x: -x[0])

    if flag:
       del  red[red_candidate[0][1]] 
       ans += 1
       flag = False
print(ans)

Solution (Python):

def findpath(v, t, edges, flow, visited):
    visited.add(v)
    for u in edges[v]:
        if u in visited:
            continue
        if flow[(v, u)] == 1:
            continue
        if u == t:
            return [v, t]
        path = findpath(u, t, edges, flow, visited)
        if path:
            return [v] + path
    return None

def max_match(R, B, edges):
    s, t = 'S', 'T'
    flow = {}
    for b in B:
        flow[(b, t)] = 0
        edges[b].append(t)  

    for r in R:
        flow[(s, r)] = 0
        for b in edges[r]:
            flow[(r, b)] = 0
            flow[(b, r)] = 1

    for r in R:
        if flow[(s, r)] == 1:
            continue
        path = findpath(r, t, edges, flow, set())
        if not path:
            continue
        path = [s] + path
        for u, v in zip(path, path[1:]):
            flow[(u, v)] = 1
            flow[(v, u)] = 0
    return flow

def solve(R, B, edges):
    flow = max_match(R, B, edges)
    match = 0
    for r in R:
        for b in edges[r]:
            match += flow[(r, b)]
    return match

N = int(input())
R = [tuple([int(x) for x in input().split()]) for _ in range(N)]
B = [tuple([int(x) for x in input().split()]) for _ in range(N)]
edges = {r:[] for r in R+B}

for r in R:
    rx, ry = r
    for b in B:
        bx, by = b
        if rx < bx and ry < by:
            edges[r].append(b)
            edges[b].append(r)

print(solve(R, B, edges))

Solution (Python):
label = {}
flow = {}
s, t = 'S', 'T'

def printpath(path):
    return
    for u, v in zip(path, path[1:]):
        print("%s -%d-> " % (label[u], flow[(u,v)]), end="")
    print("")

def printflow():
    return
    print("--flow--")
    for r in R:
        for b in edges[r]:
            print("  ", label[r], label[b], "s->r=%d"%flow[(s, r)], ", r->b=%d"%flow[(r, b)], ", b->t=%d"%flow[(b, t)])
            
        if edges[r]:
            print()

def findpath(v, t, edges, flow, visited):
    visited.add(v)
    
    for u in edges[v]:
        if u in visited:
            continue
        if flow[(v, u)] == 1:
            continue
        if u == t:
            return [v, t]
        path = findpath(u, t, edges, flow, visited)
        if path:
            return [v] + path
    return None

def max_match(R, B, edges):

    
    for b in B:
        flow[(b, t)] = 0
        flow[(t, b)] = 1
        edges[b].append(t)

    edges[s] = []
    
    for r in R:
        flow[(s, r)] = 0
        flow[(r, s)] = 1
        edges[s].append(r)

        
        for b in edges[r]:
            flow[(r, b)] = 0
            flow[(b, r)] = 1

    change = True
    while change:
        printflow()
        change = False
        for r in R:
            if flow[(s, r)] == 1:
                continue
            path = findpath(r, t, edges, flow, set([s]))
            if not path:
                continue
            
            path = [s] + path
            for u, v in zip(path, path[1:]):
                flow[(u, v)] = 1
                flow[(v, u)] = 0
            
    printflow()
    return flow

def solve(R, B, edges):
    flow = max_match(R, B, edges)

    match = 0
    for r in R:
        for b in edges[r]:
            match += flow[(r, b)]
    return match
            

N = int(input())

R = [tuple([int(x) for x in input().split()]) for _ in range(N)]
B = [tuple([int(x) for x in input().split()]) for _ in range(N)]
for i, r in enumerate(R):
    label[r] = "R%d" % (i+1)
    
for i, r in enumerate(B):
    label[r] = "B%d" % (i+1)
    
label[s] = 'S'
label[t] = 'T'

edges = {}
for r in R:
    edges[r] = []
for b in B:
    edges[b] = []

for r in R:
    rx, ry = r
    for b in B:
        bx, by = b
        if rx < bx and ry < by:
            edges[r].append(b)
            edges[b].append(r)


print(solve(R, B, edges))