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.15.1) (judge verdict: Accepted)

use std::io::Write;

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

fn main() {
    let n: usize = {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        let s = s.trim_right().to_owned();
        s.parse().unwrap()
    };

    let reds: Vec<(usize, usize)> = {
        let mut v: Vec<_> = Vec::new();
        for _ in 0..n {
            let (a, b): (usize, usize) = {
                let mut s = String::new();
                std::io::stdin().read_line(&mut s).unwrap();
                let s = s.trim_right().to_owned();
                let mut ws = s.split_whitespace();
                let a = ws.next().unwrap().parse().unwrap();
                let b = ws.next().unwrap().parse().unwrap();
                (a, b)
            };
            v.push((a, b));
        }
        v
    };

    let blues: Vec<(usize, usize)> = {
        let mut v: Vec<_> = Vec::new();
        for _ in 0..n {
            let (a, b): (usize, usize) = {
                let mut s = String::new();
                std::io::stdin().read_line(&mut s).unwrap();
                let s = s.trim_right().to_owned();
                let mut ws = s.split_whitespace();
                let a = ws.next().unwrap().parse().unwrap();
                let b = ws.next().unwrap().parse().unwrap();
                (a, b)
            };
            v.push((a, b));
        }
        v
    };

    let mut edges = vec![];
    for (red_i, &(rx, ry)) in reds.iter().enumerate() {
        for (blue_i, &(bx, by)) in blues.iter().enumerate() {
            if rx < bx && ry < by {
                edges.push((red_i, blue_i));
            }
        }
    }

    println!("{}", bipartite_matching(n, n, &edges));
}

type Graph = Vec<Vec<Edge>>;

#[derive(Debug, Clone)]
struct Edge {
    to: usize,
    cap: usize,
    rev: usize,
}

fn max_flow(source: usize, sink: usize, graph: &mut Graph) -> usize {
    let n = graph.len();

    let mut flow = 0;
    loop {
        let mut level: Vec<Option<usize>> = vec![None; n];
        bfs(source, &graph, &mut level);
        if level[sink].is_none() {
            return flow;
        }

        let mut iter: Vec<usize> = vec![0; n];

        let mut f = dfs(source, sink, std::usize::MAX, graph, &level, &mut iter);
        while f > 0 {
            flow += f;
            f = dfs(source, sink, std::usize::MAX, graph, &level, &mut iter);
        }
    }
}

fn bfs(source: usize, graph: &Graph, level: &mut Vec<Option<usize>>) {
    use std::collections::VecDeque;

    let mut queue = VecDeque::new();
    level[source] = Some(0);
    queue.push_front(source);
    while let Some(v) = queue.pop_back() {
        for e in &graph[v] {
            let l = level[v].unwrap();
            if e.cap > 0 && level[e.to].is_none() {
                level[e.to] = Some(l + 1);
                queue.push_front(e.to);
            }
        }
    }
}

fn dfs(
    v: usize,
    t: usize,
    f: usize,
    graph: &mut Graph,
    level: &Vec<Option<usize>>,
    iter: &mut Vec<usize>,
) -> usize {
    if v == t {
        return f;
    }
    for i in iter[v]..graph[v].len() {
        let e = graph[v][i].clone();
        if e.cap > 0 && level[v] < level[e.to] {
            let d = dfs(e.to, t, std::cmp::min(f, e.cap), graph, level, iter);
            if d > 0 {
                graph[v][i].cap -= d;
                graph[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    0
}

// 頂点集合X, Yからなる二部グラフの最大マッチング
fn bipartite_matching(x: usize, y: usize, edges: &Vec<(usize, usize)>) -> usize {
    // 0~(x - 1)がX、x~(x + y - 1)がY、x + yが始点、x + y + 1が終点
    let mut graph: Graph = vec![vec![]; x + y + 2];
    let source = x + y;
    let sink = x + y + 1;

    // 始点からX
    for vertex in 0..x {
        add_edge(source, vertex, 1, &mut graph);
    }
    // Yから終点
    for vertex in x..(x + y) {
        add_edge(vertex, sink, 1, &mut graph);
    }
    // X, Y間
    for e in edges {
        let (x1, y1) = *e;
        add_edge(x1, y1 + x, 1, &mut graph);
    }

    max_flow(source, sink, &mut graph)
}

fn add_edge(from: usize, to: usize, cap: usize, graph: &mut Graph) {
    let l = graph[to].len();
    graph[from].push(Edge {
        to: to,
        cap: cap,
        rev: l,
    });
    let l = graph[from].len();
    graph[to].push(Edge {
        to: from,
        cap: 0,
        rev: l - 1,
    });
}