use std::{cmp::max, collections::VecDeque, fs::{self, File, OpenOptions}, io::{BufRead, BufReader, BufWriter, Read, Write}};
fn read_graph(rdr: &mut BufReader<File>, l: usize, k: usize) -> Vec<Vec<usize>> {
let mut adj: Vec<Vec<usize>> = vec![vec![]; l + 1];
for _ in 0..k {
let mut line = String::new();
rdr.read_line(&mut line);
let mut it = line.split_whitespace().map(|x| x.parse::<usize>().unwrap());
let u = it.next().unwrap();
let v = it.next().unwrap();
adj[u].push(v);
}
adj
}
fn main() {
// read
let mut file = File::open("cuplaj.in").unwrap();
let mut rdr = BufReader::new(file);
let mut line = String::new();
rdr.read_line(&mut line);
let mut it = line.split_whitespace().map(|x| x.parse::<usize>().unwrap());
let l = it.next().unwrap();
let r = it.next().unwrap();
let k = it.next().unwrap();
let mut adj: Vec<Vec<usize>> = vec![vec![]; l + 1];
for _ in 0..k {
let mut line = String::new();
rdr.read_line(&mut line);
let mut it = line.split_whitespace().map(|x| x.parse::<usize>().unwrap());
let u = it.next().unwrap();
let v = it.next().unwrap();
adj[u].push(v);
}
let mut matchL: Vec<i32> = vec![-1; l + 1];
let mut matchR: Vec<i32> = vec![-1; r + 1];
let mut dist = vec![-1; l + 1];
let mut matching = 0;
while bfs(&adj, &matchL, &matchR, &mut dist, l) {
for u in 1..=l {
if matchL[u] == -1 && dfs(u, &adj, &mut matchL, &mut matchR, &mut dist) {
matching += 1;
}
}
}
// dbg!(&matchL, &matchR, matching);
// write
let ofile= OpenOptions::new().create(true).write(true).truncate(true).open("cuplaj.out").unwrap();
let mut out = BufWriter::new(ofile);
writeln!(out, "{} ", matching);
for u in 1..=l {
if matchL[u] != -1 {
writeln!(out, "{} {}", u, matchL[u]);
}
}
}
fn bfs(adj: &Vec<Vec<usize>>, matchL: &Vec<i32>, matchR: &Vec<i32>, dist: &mut Vec<i32>, l: usize) -> bool {
// dbg!("BFS: ", &matchL, &matchR, &dist);
let mut d: VecDeque<usize> = VecDeque::new();
for u in 1..=l {
if matchL[u] == -1 {
d.push_back(u);
dist[u] = 0;
} else {
dist[u] = -1;
}
}
let mut found_path = false;
// dbg!("BFS 2: ", &dist, &d);
let mut path_len = 1_000_000_000;
while !d.is_empty() {
let u = d.pop_front().unwrap();
for v in adj[u].iter() {
let w = matchR[*v];
// dbg!(u, v, w);
// dbg!(&dist, &d);
if w == -1 {
found_path = true;
path_len = dist[u];
} else if (dist[w as usize] == -1 && dist[u] < path_len) {
d.push_back(w as usize);
dist[w as usize] = dist[u] + 1;
}
}
}
// dbg!("BFS 3: ", &dist, &d);
return found_path;
}
fn dfs (u: usize, adj: &Vec<Vec<usize>>, matchL: &mut Vec<i32>, matchR: &mut Vec<i32>, dist: &mut Vec<i32>) -> bool {
// dbg!("DFS: ", u, &matchL, &matchR, &dist);
for &v in &adj[u] {
let w = matchR[v];
if w == -1 || (dist[w as usize] == dist[u] + 1 && dfs(w as usize, adj, matchL, matchR, dist)) {
matchR[v] = u as i32;
matchL[u] = v as i32;
return true;
}
}
dist[u] = -1;
return false;
}