#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
class Dinic {
private:
struct Edge {
int from, to, flow, cap;
};
int nodes, source, sink;
const int INF = (1 << 30);
vector <int> last, level;
vector <Edge> edges;
vector <vector <pair <int, int>>> graph;
bool bfs() {
fill(level.begin(), level.end(), INF);
level[source] = 0;
queue <int> q;
q.push(source);
while (!q.empty()) {
int node = q.front();
q.pop();
for (auto& it : graph[node]) {
int flow = edges[it.second].flow;
int cap = edges[it.second].cap;
if (flow < cap && level[it.first] > level[node] + 1) {
level[it.first] = level[node] + 1;
q.push(it.first);
}
}
}
return (level[sink] != INF);
}
int dfs(int node, int deltaFlow) {
if (node == sink || deltaFlow == 0) {
return deltaFlow;
}
else {
for (int& p = last[node]; p < graph[node].size(); ++p) {
int nextNode = graph[node][p].first;
int edgeId = graph[node][p].second;
int flow = edges[edgeId].flow;
int cap = edges[edgeId].cap;
if (level[nextNode] == level[node] + 1 && flow < cap) {
int pushed = dfs(nextNode, min(deltaFlow, cap - flow));
if (pushed) {
edges[edgeId].flow += pushed;
edges[edgeId ^ 1].flow -= pushed;
return pushed;
}
}
}
return 0;
}
}
public:
Dinic(int _nodes, int _source, int _sink) {
nodes = _nodes;
source = _source;
sink = _sink;
last.resize(nodes, 0);
level.resize(nodes, 0);
graph.resize(nodes, vector <pair <int, int>>());
}
void addEdge(int from, int to, int cap) {
Edge forward = { from, to, 0, cap };
Edge backward = { to, from, 0, 0 };
graph[from].push_back({ to, edges.size() });
edges.push_back(forward);
graph[to].push_back({ from, edges.size() });
edges.push_back(backward);
}
int maxFlow() {
int flow = 0;
while (bfs()) {
fill(last.begin(), last.end(), 0);
int deltaFlow = dfs(source, INF);
while (deltaFlow > 0) {
flow += deltaFlow;
deltaFlow = dfs(source, INF);
}
}
return flow;
}
vector <pair <int, int>> getSaturatedEdges() {
vector <pair <int, int>> saturatedEdges;
for (auto& it : edges) {
if (it.flow == 1 && it.flow == it.cap && it.from != source && it.to != sink) {
saturatedEdges.push_back({ it.from, it.to });
}
}
return saturatedEdges;
}
};
int main() {
ifstream fin("harta.in");
ofstream fout("harta.out");
int N;
fin >> N;
Dinic flow(2 * N + 2, 0, 2 * N + 1);
for (int i = 1; i <= N; ++i) {
int outDeg, inDeg;
fin >> outDeg >> inDeg;
flow.addEdge(0, i, outDeg);
flow.addEdge(i + N, 2 * N + 1, inDeg);
}
for (int i = 1; i <= N; ++i) {
for (int j = N + 1; j <= 2 * N; ++j) {
if (i + N != j) {
flow.addEdge(i, j, 1);
}
}
}
flow.maxFlow();
vector <pair <int, int>> edges = flow.getSaturatedEdges();
fout << edges.size() << "\n";
for (auto& it : edges) {
fout << it.first << " " << it.second - N << "\n";
}
fin.close();
fout.close();
return 0;
}