#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int NMAX = 20505;
const int INF = 0x3f3f3f3f;
int N, M, E;
vector<int> G[NMAX];
int L[NMAX], R[NMAX];
void read() {
scanf("%d%d%d", &N, &M, &E);
int x, y;
for (int edgeIdx = 0; edgeIdx < E; edgeIdx++) {
scanf("%d%d", &x, &y);
G[x].push_back(y + N);
}
}
bool bfs(vector<int>& shortestDist) {
shortestDist.assign(N + 1, INF);
queue<int> Q;
for (int node = 1; node <= N; node++) {
if (!L[node]) {
shortestDist[node] = 0;
Q.push(node);
}
}
bool foundImprovement = false;
while (!Q.empty()) {
int node = Q.front();
Q.pop();
for (auto& nodeRight : G[node]) {
if (!R[nodeRight]) {
foundImprovement = true;
}
if (R[nodeRight] && shortestDist[R[nodeRight]] == INF) {
shortestDist[R[nodeRight]] = shortestDist[node] + 1;
Q.push(R[nodeRight]);
}
}
}
return foundImprovement;
}
bool dfs(int node, vector<bool>& visited) {
if (visited[node]) {
return false;
}
visited[node] = true;
for (auto& nodeRight : G[node]) {
if (!R[nodeRight] || dfs(R[nodeRight], visited)) {
L[node] = nodeRight;
R[nodeRight] = node;
return true;
}
}
return false;
}
void solve() {
bool foundImprovement = true;
int matchSize = 0;
vector<bool> visited;
while (foundImprovement) {
foundImprovement = false;
visited.assign(N + 1, false);
for (int node = 1; node <= N; node++) {
if (!L[node] && dfs(node, visited)) {
foundImprovement = true;
matchSize++;
}
}
}
printf("%d\n", matchSize);
for (int leftNode = 1; leftNode <= N; leftNode++) {
if (L[leftNode]) {
printf("%d %d\n", leftNode, L[leftNode] - N);
}
}
}
int main() {
freopen("cuplaj.in", "r", stdin);
freopen("cuplaj.out", "w", stdout);
read();
solve();
return 0;
}