Cod sursa(job #1394931)

Utilizator rootsroots1 roots Data 20 martie 2015 20:46:40
Problema Cuplaj maxim in graf bipartit Scor 50
Compilator cpp Status done
Runda Arhiva educationala Marime 3.63 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;
    
    // must use list iterators, and not vector iterators
    // because the iterators from vector change when the size of the vector is doubled
    // and the whole container is reallocated to different addresses
    // the same does not apply to lists, where the addresses of the iterators remain fixed
    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));
        
        Gf[x].back().revEdge = &*Gf[y + L].rbegin();
        Gf[y + L].back().revEdge = &*Gf[x].rbegin();
    }
    
    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();
    }
    
    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 = 1; i <= L + R; ++ 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) {
                if (fromNode < toNode) {
                    match[fromNode] = toNode;
                } else {
                    match[fromNode] = 0;
                }
            }
            
            (*path[node]).f1 += cfpath;
            (*((*path[node]).revEdge)).f1 -= cfpath;
        }
        printf("\n");
    }
}

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;
}