Pagini recente » Cod sursa (job #2411628) | Cod sursa (job #2628870) | Cod sursa (job #2188651) | Cod sursa (job #272987) | Cod sursa (job #1394989)
#include <fstream>
#include <list>
#include <queue>
#define MAXV 10003
using namespace std;
ifstream in("cuplaj.in");
ofstream out("cuplaj.out");
class edge {
public:
int fromNode, toNode, c, f1;
// cannot use iterators, because c++ iterators cannot be circular (so far)
// (ownership problem maybe??, iterators own the objects they point to)
// instead use pointers to the data the iterators point to
// (basically, replace iterators with pointers)
edge* revEdge;
edge(int fromNode, int toNode, int c, int f1) {
this -> fromNode = fromNode;
this -> toNode = toNode;
this -> c = c;
this -> f1 = f1;
}
};
int L, R, E;
list <edge> Gf[2 * MAXV];
int s, t;
list <edge>::iterator path[2 * MAXV];
int maxFlow = 0;
int match[MAXV];
inline void readAndBuild() {
in >> L >> R >> E;
s = L + R + 1;
t = L + R + 2;
int x, y;
for (int e = 0; e < E; ++ e) {
in >> x >> y;
Gf[x].push_back(*new edge(x, y + L, 1, 0));
Gf[y + L].push_back(*new edge(y + L, x, 0, 0));
// the pointer to the reverse edge is the address(&) of what the iterator points to(*)
// also, very important, must use list instead of vector
// vector is reallocated every time it runs out of space (its capacity gets doubled then)
// so the addresses of the data changes
// for list, the reallocation never happens on insertions (this means both insert and push_back)
Gf[x].back().revEdge = &*Gf[y + L].rbegin();
Gf[y + L].back().revEdge = &*Gf[x].rbegin();
}
// add the source / supersource to form a network
// s connected only to L
for (int i = 1; i <= L; ++ i) {
Gf[s].push_back(*new edge(s, i, 1, 0));
Gf[i].push_back(*new edge(i, s, 0, 0));
Gf[s].back().revEdge = &*Gf[i].rbegin();
Gf[i].back().revEdge = &*Gf[s].rbegin();
}
// add sink / supersink to form a network
// t connected only to R
for (int i = 1 + L; i <= R + L; ++ i) {
Gf[i].push_back(*new edge(i, t, 1, 0));
Gf[t].push_back(*new edge(t, i, 0, 0));
Gf[i].back().revEdge = &*Gf[t].rbegin();
Gf[t].back().revEdge = &*Gf[i].rbegin();
}
}
inline bool bfs() {
queue <int> q;
q.push(s);
for (int i = L + R; i > 0; -- i) {
path[i] = Gf[0].end(); // means "not set"
}
path[s] = Gf[0].end();
path[t] = Gf[0].end();
for (int node = q.front(); !q.empty(); node = q.front()) {
q.pop();
if (node == t) {
return true;
}
for (list <edge>::iterator it = Gf[node].begin(); it != Gf[node].end(); ++ it) {
if (path[(*it).toNode] == Gf[0].end() && (*it).f1 < (*it).c) {
path[(*it).toNode] = it;
q.push((*it).toNode);
}
}
}
return false;
}
inline void bipartiteMatchWithEdmondsKarp() {
for (bool isPath = bfs(); isPath; isPath = bfs()) {
int cfpath = (*path[t]).c - (*path[t]).f1;
for (int node = (*path[t]).fromNode; node != s; node = (*path[node]).fromNode) {
if (cfpath > (*path[node]).c - (*path[node]).f1) {
cfpath = (*path[node]).c - (*path[node]).f1;
}
}
maxFlow += cfpath;
for (int node = t; node != s; node = (*path[node]).fromNode) {
int fromNode = (*path[node]).fromNode;
int toNode = node;
if (fromNode != s && fromNode != t && toNode != s && toNode != t) {
// due to encoding (x in R became x+L)
// if from is less than to we have a normal edge, which means match created
// otherwise, it means that a match was cancelled
if (fromNode < toNode) {
match[fromNode] = toNode;
} else {
match[toNode - L] = 0;
}
}
(*path[node]).f1 += cfpath;
// this is why all the trouble with the cyclic pointers
// because memory limit does not allow a flow matrix,
// we needed a fast way to update the back flow
(*((*path[node]).revEdge)).f1 -= cfpath;
}
}
}
inline void printResult() {
out << maxFlow << '\n';
for (int i = 1; i <= L; ++ i) {
if (match[i]) {
out << i << ' ' << match[i] - L << '\n';
}
}
}
int main() {
readAndBuild();
bipartiteMatchWithEdmondsKarp();
printResult();
return 0;
}