Cod sursa(job #1394958)

Utilizator rootsroots1 roots Data 20 martie 2015 21:20:24
Problema Cuplaj maxim in graf bipartit Scor 50
Compilator cpp Status done
Runda Arhiva educationala Marime 4.56 kb
#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[fromNode] = 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;
}