Cod sursa(job #3121852)

Utilizator patrixKovacs Patrik patrix Data 15 aprilie 2023 17:51:12
Problema Cuplaj maxim in graf bipartit Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.84 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;
        bool matched = false;

        Edge(Node* from, Node* to): from(from), to(to) {}
    };

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

    int id;
    bool main;
    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) {
    if (start_node.matched) {
        return;
    }
    std::list<EdgeRef> res;
    std::transform(start_node.edges.begin(), start_node.edges.end(), std::inserter(res, res.end()), [](auto& edge) -> EdgeRef { 
        return {&edge, nullptr}; 
    });

    auto it = res.begin();
    bool finished = false;
    while (it != res.end()) {
        // std::cout << "checking edge " << it->edge->from->id << ' ' << it->edge->to->id << '\n';
        if (it->edge->to->matched == nullptr) {
            finished = true;
            // std::cout << "finished\n";
            break;
        }
        for (auto& edge: it->edge->to->edges) {
            if (edge.matched != it->edge->matched) {
                res.emplace_back(&edge, &(*it));
            }
        }
        ++it;
    }
    if (finished) {
        auto ptr = &(*it);
        while (ptr != nullptr) {
            // std::cout << "operating edge " << ptr->edge->from->id << ' ' << ptr->edge->to->id << '\n';
            ptr->edge->matched = !ptr->edge->matched;
            // std::cout << "invert edge " << ptr->edge->from->id << ' ' << ptr->edge->to->id << " to " << ptr->edge->matched << '\n';
            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;
                // std::cout << "node " << ptr->edge->from->id << " pointed to node " << ptr->edge->to->id << '\n';
                ptr->edge->to->matched = &(*pos);
                // std::cout << "node " << ptr->edge->to->id << " pointed to node " << pos->to->id << '\n';
            } else {
                ptr->edge->from->matched = nullptr;
            }
            ptr = ptr->back_ref;
        }
    }
}


// void print_status(const std::vector<Node>& nodes) {
//     for (const auto& node: nodes) {
//         std::cout << node.id << ' ';
//         if (node.matched == nullptr) {
//             std::cout << "null";
//         } else {
//             std::cout << node.matched->to->id;
//         }
//         std::cout << '\n';
//     }
// }

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, true);
    }
    for (int i = 1; i <= m; ++i) {
        nodes_b[i-1] = Node(i, false);
    }
    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]);
        nodes_b[b-1].edges.emplace_back(&nodes_b[b-1], &nodes_a[a-1]);
    }

    int count = 0;
    for (auto& node: nodes_a) {
        // std::cout << "run for node " << node.id << '\n';
        bfs(node);
        // print_status(nodes_a);
        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';
        }
    }


}