#include <cstdio>
#include <cassert>
#include <algorithm>
#include <vector>
#include <list>
#include <queue>
#include <cstdlib>
#include <cstring>
using namespace std;
#define _submit
#ifdef _submit
#define InFile "cuplaj.in"
#define OtFile "cuplaj.out"
#else
#define InFile "fis.in"
#define OtFile "fis.out"
#endif
class edge {
private:
int toNod, capacity, *flow;
edge(int N, int p, int* f) {
toNod = N;
capacity = p;
flow = f;
}
friend class graph;
};
class graph {
private:
vector< list<edge> > adiac;
public:
graph(int N) { adiac.resize(N + 1); }
void addEdge(int n1, int n2, int cap) {
int* f = new int(0);
adiac[n1].push_back(edge(n2, cap, f));
adiac[n2].push_back(edge(-n1, cap, f));
}
int size() { return adiac.size() - 1; }
bool getAugmentingPath(int nod, int endNod, vector<char>& visited, vector<int*>& pathFlows, int& minFlow) {
visited[nod] = 1;
if (nod == endNod)
return true;
for (auto i = adiac[nod].begin(); i != adiac[nod].end(); ++i) {
int neigh = i->toNod > 0 ? i->toNod : -i->toNod;
if (visited[neigh])
continue;
bool isForwardArc = i->toNod > 0 ? true : false;
bool isAvailable = false;
if (isForwardArc && *(i->flow) < i->capacity) {
isAvailable = true;
if (i->capacity - *(i->flow) < minFlow)
minFlow = i->capacity - *(i->flow);
}
else if (!isForwardArc && *(i->flow) > 0) {
isAvailable = true;
if (*(i->flow) < minFlow)
minFlow = *(i->flow);
*(i->flow) = -(*(i->flow));
}
if (isAvailable) {
if (getAugmentingPath(neigh, endNod, visited, pathFlows, minFlow)) {
pathFlows.push_back(i->flow);
return true;
}
}
}
return false;
}
#define MAXEDGES 11000
#define INFINIT 100000
int FordFulkerson(int source, int sink) {
int s = 0;
vector<int*> pathFlows;
pathFlows.reserve(MAXEDGES);
vector<char> visited(size() + 1);
while (true) {
int minFlow = INFINIT;
visited.assign(size() + 1, 0);
pathFlows.clear();
getAugmentingPath(source, sink, visited, pathFlows, minFlow);
if (!pathFlows.size())
break;
s += minFlow;
for (auto i = pathFlows.begin(); i != pathFlows.end(); ++i) {
if (**i < 0) {
**i = -(**i);
**i -= minFlow;
}
else
**i += minFlow;
}
}
return s;
}
void printBipartiteFlow(int source, int sink, int offset1, int offset2) {
for (int i = 1; i < size() + 1; i++) {
if (i != source)
for (auto j = adiac[i].begin(); j != adiac[i].end(); ++j)
if (j->toNod > 0 && j->toNod != sink && *j->flow != 0)
printf("%d %d\n", i - offset1, j->toNod - offset2);
}
}
};
int main() {
assert(freopen(InFile, "r", stdin));
assert(freopen(OtFile, "w", stdout));
int N, M, E;
scanf("%d%d%d", &N, &M, &E);
graph* G = new graph(N + M + 2);
for (int i = 0; i < E; i++) {
int a, b;
scanf("%d%d", &a, &b);
G->addEdge(a + 1, b + N + 1, 1);
}
for (int i = 2; i <= N + 1; i++)
G->addEdge(1, i, 1);
for (int i = N + 2; i <= N + M + 1; i++)
G->addEdge(i, N + M + 2, 1);
printf("%d\n", G->FordFulkerson(1, N + M + 2));
G->printBipartiteFlow(1, N + M + 2, 1, N + 1);
return 0;
}