Cod sursa(job #1395700)

Utilizator rootsroots1 roots Data 21 martie 2015 12:57:22
Problema Cuplaj maxim in graf bipartit Scor 40
Compilator cpp Status done
Runda Arhiva educationala Marime 3.85 kb
#include <fstream>
#include <vector>
#include <queue>

#define MAXV 10001

using namespace std;

ifstream in("cuplaj.in");
ofstream out("cuplaj.out");

int L, R, E;
vector <int> G[2 * MAXV];
bool vertexInF[2 * MAXV];
int dist[2 *MAXV];
int match[2 * MAXV];
bool vertexMarked[2 * MAXV];
int father[2 * MAXV];
int firstPath, secondPath;
int maxMatch = 0;

inline void readAndBuild() {
    in >> L >> R >> E;
    
    int x, y;
    for (int e = 0; e < E; ++ e) {
        in >> x >> y;
        
        G[x].push_back(y + L);
        G[y + L].push_back(x);
    }
}

inline bool findAugmentingPath() {
    queue <int> qF; // qF contains all the vertices that are added in F, in the order they appear
    for (int node = L + R; node > 0; -- node) {
        if (match[node] == 0) { // if node is unmatched
            qF.push(node);
            vertexInF[node] = true;
            dist[node] = 0;
        } else { // if node is matched
            vertexInF[node] = false;
            dist[node] = -1; // -1 is used to enforce that node is not in F
        }
        
        vertexMarked[node] = false; // each vertex can be processed only once
        father[node] = -1;
    }
    
    for (int node = qF.front(); !qF.empty(); node = qF.front()) {
        qF.pop();
        
        if (dist[node] % 2) continue;
        
        for (vector <int>::iterator it = G[node].begin(); it != G[node].end(); ++ it) {
            
            // check if edge is unmarked i.e. not used already
            // because we are using a bipartite graph
            // we need only to check that we are not going back
            // on the edge that ended up on node
            if (*it != father[node]) {
                if (match[*it] != 0) { // *it is present on some edge of M i.e. *it not in F
                    // root(node) ~> node -> *it -> match[*it]
                    dist[match[*it]] = dist[node] + 2;
                    dist[*it] = dist[node] + 1;
                    
                    father[match[*it]] = *it;
                    father[*it] = node;
                    
                    if (vertexMarked[*it] == false) qF.push(*it);
                    if (vertexMarked[match[*it]] == false) qF.push(match[*it]);
                } else if (dist[*it] % 2 == 0) {
                    
                    // the path is root(node) ~> node -> *it ~> root(*it)
                    // we can reconstruct the path using the array father
                    // but it is split (due to the way father is defined)
                    // into root(node) ~> node and root(*it) ~> *it
                    firstPath = node;
                    secondPath = *it;
                    return true;
                }
            }
        }
        
        vertexMarked[node] = true;
    }
    
    return false;
}

inline void bipartiteMatchingWithEdmondsBlossom() {
    for (int node = L + R; node > 0; -- node) {
        match[node] = 0;
    }
    
    for (bool isPath = findAugmentingPath(); isPath; isPath = findAugmentingPath()) {
        match[firstPath] = secondPath;
        match[secondPath] = firstPath;
        
        if (father[firstPath] != -1) {
            for (int node = father[firstPath]; node != -1; node = father[father[node]]) {
                match[node] = father[node];
                match[father[node]] = node;
            }
        }
        
        if (father[secondPath] != -1) {
            for (int node = father[secondPath]; node != -1; node = father[father[node]]) {
                match[node] = father[node];
                match[father[node]] = node;
            }
        }
        
        maxMatch ++;
    }
}

inline void printResult() {
    out << maxMatch << '\n';
    for (int i = 1; i <= L; ++ i)
        if (match[i]) {
            out << i << ' ' << match[i] - L << '\n';
        }
}

int main() {
    readAndBuild();
    bipartiteMatchingWithEdmondsBlossom();
    printResult();
    
    return 0;
}