Cod sursa(job #1394992)

Utilizator rootsroots1 roots Data 20 martie 2015 21:53:45
Problema Cuplaj maxim in graf bipartit Scor 90
Compilator cpp Status done
Runda Arhiva educationala Marime 4.37 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;
    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 node = 1; node <= L; ++ node) {
        Gf[s].push_back(new edge(s, node, 1, 0));
        Gf[node].push_back(new edge(node, s, 0 , 0));
        
        Gf[s].back() -> revEdge = *Gf[node].rbegin();
        Gf[node].back() -> revEdge = *Gf[s].rbegin();
    }
    
    for (int node = 1 + L; node <= R + L; ++ node) {
        Gf[node].push_back(new edge(node, t, 1 , 0));
        Gf[t].push_back(new edge(t, node, 0, 0));
        
        Gf[node].back() -> revEdge = *Gf[t].rbegin();
        Gf[t].back() -> revEdge = *Gf[node].rbegin();
    }
}

inline bool bfs() {
    bool sinkReached = false;
    
    queue <int> q;
    q.push(s);
    
    for (int i = L + R; i > 0; -- i) {
        path[i] = Gf[0].end();
    }
    path[s] = Gf[0].begin(); // not 0, but something else (I never need this)
    path[t] = Gf[0].end(); // initialised to 0
    
    for (int node = q.front(); !q.empty(); node = q.front()) {
        q.pop();
        
        for (list <edge*>::iterator it = Gf[node].begin(); it != Gf[node].end(); ++ it) {
            if (path[(*it) -> toNode] == Gf[0].end() && (*it) -> f1 < (*it) -> c) {
                if ((*it) -> toNode == t) {
                    sinkReached = true;
                } else {
                    path[(*it) -> toNode] = it;
                    q.push((*it) -> toNode);
                }
            }
        }
    }
    
    return sinkReached;
}

inline void bipartiteMatchingWithDinicVariation() {
    for (bool sinkReached = bfs(); sinkReached; sinkReached = bfs()) {
        for (list <edge*>::iterator it = Gf[t].begin(); it != Gf[t].end(); ++ it) {
            if (path[(*it) -> toNode] != Gf[0].end() && (*it) -> revEdge -> f1 < (*it) -> revEdge -> c) {
                int cfpath = (*it) -> revEdge -> c - (*it) -> revEdge -> f1;
                for (int node = (*it) -> toNode; node != s; node = (*path[node]) -> fromNode) {
                    if (cfpath > (*path[node]) -> c - (*path[node]) -> f1) {
                        cfpath = (*path[node]) -> c - (*path[node]) -> f1;
                    }
                }
                
                if (cfpath == 0) continue;
                maxFlow += cfpath;
                
                // we have to manually change the flow for the edge and the reverse edge
                // between the possible father (x = (*it) -> toNode) and t
                // because we do not have an iterator for this edge (x, t)
                // (we have the iterator for the reverse edge (t, x))
                (*it) -> f1 -= cfpath;
                (*it) -> revEdge -> f1 += cfpath;
                for (int node = (*it) -> toNode; node != s; node = (*path[node]) -> fromNode) {
                    int fromNode = (*path[node]) -> fromNode;
                    int toNode = (*path[node]) -> toNode;
                    
                    if (fromNode != s && fromNode != t && toNode != s && toNode != t) {
                        if (fromNode < toNode) {
                            match[fromNode] = toNode;
                        }
                    }
                    (*path[node]) -> f1 += cfpath;
                    (*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();
    bipartiteMatchingWithDinicVariation();
    printResult();
    
    return 0;
}