#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <bitset>
#define NMAX 21000
#define EMAX 250000
#define BUFF_SIZE 100001
#define min(x, y) ((x < y) ? x : y)
using namespace std;
ifstream in("cuplaj.in");
ofstream out("cuplaj.out");
char buffer[BUFF_SIZE];
int pos = 0;
void Read(int &a) {
while (!isdigit(buffer[pos]))
if (++pos == BUFF_SIZE)
in.read(buffer, BUFF_SIZE), pos = 0;
a = 0;
while (isdigit(buffer[pos]))
{
a = a * 10 + buffer[pos] - '0';
if (++pos == BUFF_SIZE)
in.read(buffer, BUFF_SIZE), pos = 0;
}
}
struct edge {
int X, Y, cap, flow;
edge(int x = 0, int y = 0, int c = 0, int f = 0) : X(x), Y(y), cap(c), flow(f) {}
};
edge edges[EMAX];
unsigned int nr_edges = 0;
struct triplet {
int Y;
edge *dir, *rev;
triplet(int y = 0, edge *DIR = nullptr, edge *REV = nullptr) : Y(y), dir(DIR), rev(REV) {}
};
vector<triplet> G[NMAX];
bitset<NMAX> mark;
queue<int> q;
int left_size, right_size;
pair<int, triplet*> father[NMAX];
int n;
void build_graph() {
int m, x, y;
edge *dir, *rev;
Read(left_size);
Read(right_size);
Read(m);
n = left_size + right_size + 2;
for (int i = 1; i <= m; i++) {
Read(x);
Read(y);
edges[++nr_edges] = edge(x + 1, y + left_size + 1, 1, 0);
dir = &edges[nr_edges];
edges[++nr_edges] = edge(y + left_size + 1, x + 1, 0, 0);
rev = &edges[nr_edges];
G[x + 1].push_back(triplet(y + left_size + 1, dir, rev));
G[y + left_size + 1].push_back(triplet(x + 1, rev, dir));
}
for (int i = 2; i < 2 + left_size; i++)
{
edges[++nr_edges] = edge(1, i, 1, 0);
dir = &edges[nr_edges];
edges[++nr_edges] = edge(i, 1, 0, 0);
rev = &edges[nr_edges];
G[1].push_back(triplet(i, dir, rev));
G[i].push_back(triplet(1, rev, dir));
}
for (int i = left_size + 2; i < n; i++)
{
edges[++nr_edges] = edge(i, n, 1, 0);
dir = &edges[nr_edges];
edges[++nr_edges] = edge(n, i, 0, 0);
rev = &edges[nr_edges];
G[i].push_back(triplet(n, dir, rev));
G[n].push_back(triplet(i, rev, dir));
}
}
void bfs(int start) {
mark.reset();
q.push(start);
mark.set(start);
father[start] = make_pair(0, nullptr);
int node;
while (!q.empty()) {
node = q.front();
for (unsigned int i = 0; i < G[node].size(); i++)
if (!mark.test(G[node][i].Y) && G[node][i].dir->cap > G[node][i].dir->flow) {
q.push(G[node][i].Y);
mark.set(G[node][i].Y);
father[G[node][i].Y] = make_pair(node, &G[node][i]);
}
q.pop();
}
}
int main() {
build_graph();
int node = 0, val;
int max_flow = 0;
for (bfs(1); mark.test(n); bfs(1)) {
for (unsigned int i = 0; i < G[n].size(); i++)
if (mark.test(G[n][i].Y) && G[n][i].rev->cap > G[n][i].rev->flow) {
node = G[n][i].Y;
val = 2;
while (node != 0)
{
if (father[node].first != 0)
val = min(val, father[node].second->dir->cap - father[node].second->dir->flow);
node = father[node].first;
}
node = G[n][i].Y;
val = min(val, G[n][i].rev->cap - G[n][i].rev->flow);
max_flow += val;
while (node != 0)
{
if (father[node].first != 0)
{
father[node].second->dir->flow += val;
father[node].second->rev->flow -= val;
}
node = father[node].first;
}
G[n][i].rev->flow += val;
G[n][i].dir->flow -= val;
}
}
out << max_flow << "\n";
for (int i = 2; i <= n - 1; i++)
for (unsigned int j = 0; j < G[i].size(); j++)
if (G[i][j].dir->flow == 1 && G[i][j].Y != n)
out << i - 1 << " " << G[i][j].Y - left_size - 1 << "\n";
return 0;
}