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 in Rust (1.42.0) (judge verdict: Accepted)

fn main() {
	let mut s = String::new();
	use std::io::Read;
	std::io::stdin().read_to_string(&mut s).unwrap();
	let mut s = s.split_whitespace();
	let n: usize = s.next().unwrap().parse().unwrap();
	let mut graph = Graph::new(2 * n + 2);
	let red = (0..n)
		.map(|_| {
			(
				s.next().unwrap().parse::<u8>().unwrap(),
				s.next().unwrap().parse::<u8>().unwrap(),
			)
		})
		.collect::<Vec<_>>();
	let blue = (0..n)
		.map(|_| {
			(
				s.next().unwrap().parse::<u8>().unwrap(),
				s.next().unwrap().parse::<u8>().unwrap(),
			)
		})
		.collect::<Vec<_>>();
	let from = 2 * n;
	let to = 2 * n + 1;
	for i in 0..n {
		graph.add_edge(from, i, 1);
		graph.add_edge(n + i, to, 1);
		for j in 0..n {
			if red[i].0 < blue[j].0 && red[i].1 < blue[j].1 {
				graph.add_edge(i, n + j, 1);
			}
		}
	}
	let ans = graph.max_flow(from, to);
	println!("{}", ans);
}
#[derive(Clone, Copy)]
pub struct Edge<T> {
	dst: u32,
	capacity: T,
	flow: T,
	reverse: u32,
}

impl<T> Edge<T> {
	pub fn new(dst: u32, capacity: T, flow: T, reverse: u32) -> Self {
		Self {
			dst,
			capacity,
			flow,
			reverse,
		}
	}
}

pub struct Graph<T> {
	edges: Vec<Vec<Edge<T>>>,
}

impl<T> Graph<T>
where
	T: Clone + Ord + num::Signed + num::traits::Bounded,
{
	pub fn new(n: usize) -> Self {
		Self {
			edges: vec![vec![]; n],
		}
	}

	pub fn size(&self) -> usize {
		self.edges.len()
	}

	pub fn add_edge(&mut self, src: usize, dst: usize, capacity: T) {
		let dstid = self.edges[dst as usize].len() as u32;
		let srcid = self.edges[src as usize].len() as u32;
		self.edges[src as usize].push(Edge::new(dst as u32, capacity, T::zero(), dstid));
		self.edges[dst as usize].push(Edge::new(src as u32, T::zero(), T::zero(), srcid));
	}

	fn bfs(&self, s: usize, t: usize, level: &mut Vec<i32>) -> bool {
		for l in level.iter_mut() {
			*l = -1;
		}
		level[s] = 0;
		let mut q = std::collections::VecDeque::new();
		q.push_back(s as u32);
		while let Some(v) = q.pop_front() {
			for e in self.edges[v as usize].iter() {
				if e.flow < e.capacity && level[e.dst as usize] < 0 {
					level[e.dst as usize] = level[v as usize] + 1;
					q.push_back(e.dst);
				}
			}
		}
		level[t] >= 0
	}

	fn dfs(&mut self, v: usize, t: usize, flow: T, level: &[i32], iter: &mut Vec<u32>) -> T {
		if v == t {
			return flow;
		}
		while (iter[v] as usize) < self.edges[v].len() {
			let i = iter[v] as usize;
			let e = self.edges[v][i].clone();
			if e.capacity > e.flow && level[v] + 1 == level[e.dst as usize] {
				let d = self.dfs(
					e.dst as usize,
					t,
					std::cmp::min(flow.clone(), e.capacity.clone() - e.flow.clone()),
					level,
					iter,
				);
				if d > T::zero() {
					self.edges[v][i].flow = self.edges[v][i].flow.clone() + d.clone();
					self.edges[e.dst as usize][e.reverse as usize].flow =
						self.edges[e.dst as usize][e.reverse as usize].flow.clone() - d.clone();
					return d;
				}
			}
			iter[v] += 1;
		}
		T::zero()
	}

	pub fn max_flow(&mut self, s: usize, t: usize) -> T {
		let mut r = T::zero();
		let mut level = vec![-1; self.size()];
		while self.bfs(s, t, &mut level) {
			let mut iter = vec![0; self.size()];
			loop {
				let flow = self.dfs(s, t, T::max_value(), &level, &mut iter);
				if flow > T::zero() {
					r = r + flow;
				} else {
					break;
				}
			}
		}
		r
	}
}