Cod sursa(job #1396054)

Utilizator rootsroots1 roots Data 21 martie 2015 23:43:23
Problema Cuplaj maxim in graf bipartit Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 2.86 kb
// O(V * E)

#include <fstream>
#include <vector>
#include <cstring>

#define MAXV 10001

using namespace std;

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

int L, R, E;
vector <int> G[MAXV];
int matchOfL[MAXV]; // i in L, matchOfL[i] in R
int matchOfR[MAXV]; // i in R, matchOfR[i] in L
bool used[MAXV];
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);
        
        // I do not need to push the reverse edge into the graph
        // because when finding an alternating (augmenting) path
        // the nodes that are on R side, always follow an edge that is in M
        // and because there is only on edge in M with some vertex v on it
        // we know that there is only one way to go back on L side
    }
}

inline bool dfs(int node) {
    
    // the dfs will present nodes only from L side
    // a node may be expanded at most once
    if (used[node]) {
        return false;
    }
    used[node] = true;
    
    // *it is always from R side
    for (vector <int>::iterator it = G[node].begin(); it != G[node].end(); ++ it) {
        
        // if *it is not matched, then it can be matched with node
        // push edge (node, *it) into M
        if (matchOfR[*it] == 0) {
            matchOfL[node] = *it;
            matchOfR[*it] = node;
            
            return true;
            
            // if *it is matched then try to follow the path
            // until we eventually end up with an unmatched node
        } else {
            bool isPath = dfs(matchOfR[*it]);
            
            // if the path ended with an unmatched node then
            // augment the path
            // (augmentation is done as the dfs goes back)
            if (isPath) {
                matchOfL[node] = *it;
                matchOfR[*it] = node;
                
                return true;
            }
        }
    }
    
    return false;
}

inline void bipartiteMatchingEdmondsBlossomSimplified() {
    bool foundPath = true;
    
    while (foundPath) {
        foundPath = false;
        
        memset(used, false, sizeof(used));
        
        for (int root = 1; root <= L; ++ root) {
            if (matchOfL[root] == 0) {
                foundPath = dfs(root);
                
                if (foundPath) {
                    maxMatch ++;
                    
                    // every time a path is found,
                    // reset the dfs
                    break;
                }
            }
        }
    }
}

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

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