Cod sursa(job #3121855)

Utilizator patrixKovacs Patrik patrix Data 15 aprilie 2023 18:15:21
Problema Cuplaj maxim in graf bipartit Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.97 kb
// https://www.infoarena.ro/problema/cuplaj

#include <fstream>
#include <vector>
#include <array>
#include <list>
#include <algorithm>

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


struct Node {
    struct Edge {
        Node* from;
        Node* to;
        int id;
        bool matched = false;

        Edge(Node* from, Node* to, const int id): from(std::move(from)), to(std::move(to)), id(id) {}
    };

    Node() = default;
    Node(const int id): id(id) {}

    int id;
    std::vector<Edge> edges = std::vector<Edge>();
    Edge* matched = nullptr;
};

struct EdgeRef {
    Node::Edge* edge;
    EdgeRef* back_ref;

    EdgeRef(Node::Edge* edge, EdgeRef* back_ref)
        : edge(std::move(edge))
        , back_ref(std::move(back_ref)) {}
};

void bfs(Node& start_node, const int max_edges) {
    if (start_node.matched) {
        return;
    }
    std::list<EdgeRef> res;
    std::vector<bool> visited(max_edges, false);
    std::transform(start_node.edges.begin(), start_node.edges.end(), std::inserter(res, res.end()), [&visited](auto& edge) -> EdgeRef { 
        visited[edge.id] = true;
        return {&edge, nullptr}; 
    });

    auto it = res.begin();
    bool finished = false;
    while (it != res.end()) {
        if (it->edge->to->matched == nullptr) {
            finished = true;
            break;
        }
        for (auto& edge: it->edge->to->edges) {
            if (!visited[edge.id] && edge.matched != it->edge->matched) {
                res.emplace_back(&edge, &(*it));
            }
        }
        ++it;
    }
    if (finished) {
        auto ptr = &(*it);
        while (ptr != nullptr) {
            ptr->edge->matched = !ptr->edge->matched;
            const auto pos = std::find_if(ptr->edge->to->edges.begin(), ptr->edge->to->edges.end(), [&ptr](const auto& edge) {
                return edge.to == ptr->edge->from;
            });
            pos->matched = ptr->edge->matched;
            if (ptr->edge->matched) {
                ptr->edge->from->matched = ptr->edge;
                ptr->edge->to->matched = &(*pos);
            } else {
                ptr->edge->from->matched = nullptr;
            }
            ptr = ptr->back_ref;
        }
    }
}

int main() {
    int n, m, e;
    in >> n >> m >> e;
    std::vector<Node> nodes_a(n), nodes_b(m);
    for (int i = 1; i <= n; ++i) {
        nodes_a[i-1] = Node(i);
    }
    for (int i = 1; i <= m; ++i) {
        nodes_b[i-1] = Node(i);
    }
    int a, b;
    for (int i = 0; i < e; ++i) {
        in >> a >> b;
        nodes_a[a-1].edges.emplace_back(&nodes_a[a-1], &nodes_b[b-1], i+i);
        nodes_b[b-1].edges.emplace_back(&nodes_b[b-1], &nodes_a[a-1], i+i+1);
    }

    int count = 0;
    for (auto& node: nodes_a) {
        bfs(node, e+e);
        if (node.matched != nullptr) {
            ++count;
        }
    }

    out << count << '\n';
    for (const auto& node: nodes_a) {
        if (node.matched != nullptr) {
            out << node.id << ' ' << node.matched->to->id << '\n';
        }
    }


}