Cod sursa(job #3241686)

Utilizator filipinezulBrain Crash filipinezul Data 2 septembrie 2024 13:56:59
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.86 kb
#include <bits/stdc++.h>
using namespace std;

struct AugmentedPath {
    bool hasPath;
    vector<pair<int, int>> path;

    AugmentedPath(bool _hasPath, const vector<pair<int, int>>& _path)
        : hasPath(_hasPath)
        , path(_path) { }

    operator bool() const {
        return hasPath;
    }
};

class EdmondsKarp { // T = O(n * m) aici T = O(n * m^2) in general
 public:
    void solve() {
        read_input();
        print_output(get_result());
    }

 private:
    int n, m, e;
    vector<vector<int>> adj;

    vector<vector<int>> cap;
    vector<pair<int, int>> cuplaj;

    void read_input() {
        ifstream fin("cuplaj.in");
        fin >> n >> m >> e;

        cap.resize(n + m + 2, vector<int>(n + m + 2, 0));
        adj.resize(n + m + 2);

        for (int i = 0, u, v; i < e; i++) {
            fin >> u >> v;
            v += n;

            adj[u].push_back(v);
            adj[v].push_back(u);

            cap[u][v] = 1;
        }

        for (int i = 1; i <= n; ++i) {
            adj[0].push_back(i); // Sursa este nodul 0
            adj[i].push_back(0);

            cap[0][i] = 1;
        }

        for (int i = n + 1; i <= n + m; ++i) {
            adj[i].push_back(n + m + 1); // Destinația este nodul n + m + 1
            adj[n + m + 1].push_back(i);

            cap[i][n + m + 1] = 1;
        }

        fin.close();
    }

    int get_result() {
        return get_maxflow(n + m + 2, 0, n + m + 1);
    }

    int get_maxflow(int nodes, int source, int sink) {
        int total_flow = 0;
        vector<vector<int>> flow(nodes, vector<int>(nodes, 0));

        while (auto res = bfs(nodes, source, sink, flow)) {
            auto& [_, path] = res;

            int minFluxPath = INT32_MAX;
            for (auto& [u, v] : path) {
                minFluxPath = min(minFluxPath, cap[u][v] - flow[u][v]);
            }

            total_flow += minFluxPath;

            for (auto& [u, v] : path) {
                flow[u][v] += minFluxPath;
                flow[v][u] -= minFluxPath;
            }
        }

        for (int i = 1; i <= n; ++i) {
            for (int j = n + 1; j <= m + n; ++j) {
                if (flow[i][j] == 1) {
                    cuplaj.push_back({i, j - n});
                }
            }
        }

        return total_flow;
    }

    AugmentedPath bfs(int nodes, int source, int sink, vector<vector<int>>& flow) {
        vector<int> p(nodes, -1);
        queue<int> q;

        q.push(source);
        p[source] = 0;

        while (!q.empty()) {
            int node = q.front();
            q.pop();

            for (auto& neigh : adj[node]) {
                if (p[neigh] == -1 && flow[node][neigh] < cap[node][neigh]) {
                    p[neigh] = node;
                    q.push(neigh);
                }
            }
        }

        if (p[sink] == -1) {
            return {false, {}};
        }

        vector<pair<int, int>> path;
        int node = sink;

        do {
            path.push_back({p[node], node});
            node = p[node];
        } while (node);

        reverse(path.begin(), path.end());
        return {true, path};
    }

    void print_output(int result) {
        ofstream fout("cuplaj.out");
        fout.tie(0);

        fout << result << "\n";

        for (const auto& edge : cuplaj) {
            fout << edge.first << " " << edge.second << "\n";
        }

        fout.close();
    }
};

class HopcroftKarp { // T = O(sqrt(n) * m)
 public:
    void solve() {
        read_input();
        print_output(get_result());
    }

 private:
    int n, m, e;
    vector<vector<int>> adj;
    vector<int> pairU, pairV, dist;

    void read_input() {
        ifstream fin("cuplaj.in");
        fin.tie(0);
        fin >> n >> m >> e;

        adj.resize(n + 1);
        pairU.assign(n + 1, 0);
        pairV.assign(m + 1, 0);
        dist.assign(n + 1, 0);

        for (int i = 0, u, v; i < e; i++) {

            fin >> u >> v;
            adj[u].push_back(v);
        }

        fin.close();
    }

    bool bfs() {
        queue<int> q;
        for (int u = 1; u <= n; ++u) {
            if (pairU[u] == 0) {
                dist[u] = 0;
                q.push(u);
            } else {
                dist[u] = INT_MAX;
            }
        }
        dist[0] = INT_MAX;

        while (!q.empty()) {
            int u = q.front();
            q.pop();

            if (dist[u] < dist[0]) {
                for (int v : adj[u]) {
                    if (dist[pairV[v]] == INT_MAX) {
                        dist[pairV[v]] = dist[u] + 1;
                        q.push(pairV[v]);
                    }
                }
            }
        }

        return dist[0] != INT_MAX;
    }

    bool dfs(int u) {
        if (u != 0) {
            for (int v : adj[u]) {
                if (dist[pairV[v]] == dist[u] + 1) {
                    if (dfs(pairV[v])) {
                        pairV[v] = u;
                        pairU[u] = v;

                        return true;
                    }
                }
            }
            dist[u] = INT_MAX;
            return false;
        }
        return true;
    }

    int get_result() {
        int matching = 0;

        while (bfs()) {
            for (int u = 1; u <= n; ++u) {
                if (pairU[u] == 0 && dfs(u)) {
                    matching++;
                }
            }
        }

        return matching;
    }

    void print_output(int result) {
        ofstream fout("cuplaj.out");
        fout.tie(0);

        fout << result << "\n";
        for (int u = 1; u <= n; ++u) {
            if (pairU[u] != 0) {
                fout << u << " " << pairU[u] << "\n";
            }
        }

        fout.close();
    }
};

int main() {
    ios::sync_with_stdio(false);
    //auto* task = new (nothrow) EdmondsKarp();
    auto* task = new (nothrow) HopcroftKarp();

    if (!task) {
        cerr << "new failed\n";
        return -1;
    }

    task->solve();
    delete task;

    return 0;
}