Cod sursa(job #1437646)

Utilizator crucerucalinCalin-Cristian Cruceru crucerucalin Data 18 mai 2015 09:34:58
Problema Cuplaj maxim in graf bipartit Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 2.95 kb
#include <fstream>
#include <vector>

using AdjLists = std::vector<std::vector<int>>;

constexpr auto NULL_VERTEX = -1;


///
// This is equivalent to a breath-first graph traversal in which we are trying
// to augment the matching with the path starting at vertex u.
//
// Augmenting the matching means finding an alternating path
// (formed by matched - unmatched - matched -.. nodes) and then, while returning
// from recursion, update the edges which are part of the matching accordingly.
///
bool
match(
        int u,
        const AdjLists &graph,
        std::vector<int> &leftVertices,
        std::vector<int> &rightVertices,
        std::vector<bool> &visited)
{
    // First check if this node has been previously visited. We want to augment
    // the matching with disjoint shortest-paths.
    if (visited[u])
        return false;

    visited[u] = true;

    // Try to match this node with a node from the right side which is not
    // matched.
    for (auto &v : graph[u])
        if (rightVertices[v] == NULL_VERTEX) {
            leftVertices[u] = v;
            rightVertices[v] = u;

            return true;
        }

    // If such a node does not exist, try to match the nodes each of this
    // node's neighbors is already matched to with other nodes than v's
    // neighbors the intent to match u and v in the next iteration step.
    for (auto &v : graph[u])
        if (match(rightVertices[v], graph, leftVertices, rightVertices,
                    visited)) {
            leftVertices[u] = v;
            rightVertices[v] = u;

            return true;
        }

    return false;
}

int main()
{
    std::ios::sync_with_stdio(false);

    std::ifstream fin{"cuplaj.in"};
    std::ofstream fout{"cuplaj.out"};
    int L, R, M;

    fin >> L >> R >> M;

    AdjLists graph(L);

    for (auto i = 0; i < M; ++i) {
        int x, y;

        fin >> x >> y;
        graph[x - 1].emplace_back(y - 1);
    }

    // By default all vertices are matched to the null vertex.
    std::vector<int> leftVertices(L, NULL_VERTEX);
    std::vector<int> rightVertices(R, NULL_VERTEX);
    std::vector<bool> visited(graph.size());
    bool changed;

    // This is done sqrt(V) times.
    do {
        changed = false;
        std::fill(visited.begin(), visited.end(), false);

        for (auto i = 0u; i < graph.size(); ++i)
            if (leftVertices[i] == NULL_VERTEX)
                changed = changed || match(i, graph, leftVertices,
                                            rightVertices, visited);
    } while (changed);

    // Trivial step: reconstruct the matching.
    //
    // First, count its size.
    auto matching = 0;

    for (auto i = 0u; i < graph.size(); ++i)
        if (leftVertices[i] != NULL_VERTEX)
            ++matching;

    // Then print all the edges it contains.
    fout << matching << '\n';
    for (auto i = 0u; i < graph.size(); ++i)
        if (leftVertices[i] != NULL_VERTEX)
            fout << i + 1 << ' ' << leftVertices[i] + 1 << '\n';

    return 0;
}