///O(n*m*m)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#define INFINITY 999999999
int l, r, e;
using namespace std;
class Graf{
private:
int noNodes;
int noEdges;
vector<vector<pair<int, int>>> graf_c;
bool fromZero;
bool oriented;
bool hasCosts;
private:
bool constructSTNesaturatedBF(int s, int t, vector<vector<int>>& f,
vector<vector<int>>& graf_t, vector<int>& tata, vector<bool>& viz);
void revizFlux(int s, int t, vector<vector<int>>& f, vector<int>& tata, int& ip);
public:
Graf(int noNodes_, int noEdges_, const vector<vector<int>>& edges, bool fromZero_, bool oriented_, bool hasCosts_);
int EndmondsKarp(vector<vector<int>>& f);
int getNodes(){
return noNodes;
}
~Graf() = default;
};
void citireFisier(int& n, int &m, vector<vector<int>>& G);
void testEdmondsKarp(Graf& my_graf);
int main()
{
int n, m;
vector<vector<int>> G;
citireFisier(n, m, G);
Graf my_graf{n, m, G, true, true, true};
testEdmondsKarp(my_graf);
return 0;
}
void citireFisier(int& n, int &m, vector<vector<int>>& G){
int x, y;
ifstream fin("cuplaj.in");
fin>>l>>r>>e;
for(int i = 1; i <= e; ++i){
fin>>x>>y;
G.push_back({x, y + l, 1});
}
for(int i = 1; i <= l; ++i){
G.push_back({0, i, 1});
}
for(int i = 1; i <= r; ++i){
G.push_back({i + l, l + r + 1, 1});
}
m = l + r + e;
n = l + r + 2;
fin.close();
}
void testEdmondsKarp(Graf& my_graf){
vector<vector<int>> f(my_graf.getNodes() + 1, vector<int>(my_graf.getNodes()+ 1, 0));
ofstream fout("cuplaj.out");
fout<<my_graf.EndmondsKarp(f)<<endl;
for(int i = 1; i <= l; ++i){
for(int j = 1; j <= r; ++j){
if(f[i][j + l] == 1){
fout<<i<<" "<<j<<endl;
}
}
}
fout.close();
}
Graf::Graf(int noNodes_, int noEdges_, const vector<vector<int>> &edges, bool fromZero_, bool oriented_, bool hasCosts_) {
noNodes = noNodes_;
noEdges = noEdges_;
fromZero = fromZero_;
oriented = oriented_;
hasCosts = hasCosts_;
if(hasCosts)
graf_c.resize(noNodes+1);
for(auto& edge:edges){
int x = edge[0], y = edge[1];
if(hasCosts) {
int z = edge[2];
graf_c[x].push_back(make_pair(y, z));
if (!oriented)
graf_c[y].push_back(make_pair(x, z));
}
}
}
bool Graf::constructSTNesaturatedBF(int s, int t, vector<vector<int>>& f,
vector<vector<int>>& graf_t, vector<int>& tata, vector<bool>& viz){
int i, v, c;
fill(viz.begin(), viz.end(), false);
queue<int> C;
C.push(s);
viz[s] = true;
while(!C.empty()) {
i = C.front();
if(i == t){
C.pop();
continue;
}
for(auto& j:graf_c[i]) {
v = j.first; c = j.second;
if (!viz[v] && c > f[i][v]) { ///arc direct
C.push(v);
viz[v] = 1;
tata[v] = i;
if(v == t)
return true;
}
}
for(auto& j:graf_t[i]){
v = j;
if(viz[v] == 0 && f[v][i] > 0){ ///arc invers
C.push(v);
viz[v] = 1;
tata[v] = -i;
if(v == t)
return true;
}
}
C.pop();
}
if(viz[t])
return true;
return false;
}
void Graf::revizFlux(int s, int t, vector<vector<int>>& f, vector<int>& tata, int& ip){
int nod = t, parent, mod_nod;
do{
mod_nod = abs(nod);
parent = tata[mod_nod];
if(parent >= 0){
f[parent][mod_nod] += ip;
}else{
f[mod_nod][abs(parent)] -= ip;
}
nod = tata[mod_nod];
}while(abs(nod) != s);
}
int Graf::EndmondsKarp(vector<vector<int>>& f){
short offset = fromZero?1:0;
int sum = 0, s = 1 - offset, t = noNodes - offset, minim;
vector<vector<int>> graf_t(noNodes + 1);
vector<bool> viz(noNodes + 1, false);
vector<int> tata(noNodes + 1, 0);
vector<vector<int>> c(noNodes + 1, vector<int>(noNodes + 1, 0));
for(int i = 1 - offset; i <= noNodes - offset; ++i){
for(auto& j:graf_c[i]){
c[i][j.first] = j.second;
graf_t[j.first].push_back(i);
}
}
while(constructSTNesaturatedBF(s, t, f, graf_t, tata, viz)){
for (auto& node: graf_t[t]) {
if (f[node][t] == c[node][t] || !viz[node])
continue;
tata[t] = node;
minim = INFINITY;
int nod = t, parent, mod_nod;
do{
mod_nod = abs(nod);
parent = tata[mod_nod];
if(parent >= 0){
minim = min(minim, c[parent][mod_nod] - f[parent][mod_nod]);
}else{
minim = min(minim, f[mod_nod][abs(parent)]);
}
nod = tata[mod_nod];
}while(abs(nod) != s && minim != 0);
if (minim == 0)
continue;
revizFlux(s, t, f, tata, minim);
sum += minim;
}
}
return sum;
}