Cod sursa(job #3270935)

Utilizator FunnyStockyMihnea Andreescu FunnyStocky Data 24 ianuarie 2025 21:27:37
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.27 kb
#include <bits/stdc++.h>
using namespace std;

class BipartiteMatcher {
private:
    int n, m, e;
    vector<vector<int>> g;  // Listele de adiacență pentru nodurile din stânga
    vector<int> pi, pj;     // pi[i] = nodul din dreapta cu care e legat i (sau -1 dacă nu e legat)
                            // pj[j] = nodul din stânga cu care e legat j (sau -1 dacă nu e legat)
    vector<bool> vis;       // Mark de vizitare pentru DFS

    // Funcție de legare a nodului i din stânga cu j din dreapta
    void pairUp(int i, int j) {
        pi[i] = j;
        pj[j] = i;
    }

    // DFS recursiv pentru găsirea unui drum de augmentare plecând din nodul 'a'
    bool dfs(int a) {
        if(vis[a]) return false;
        vis[a] = true;

        for(int b : g[a]) {
            // Dacă b nu este încă împerecheat, îl împerechem direct
            if(pj[b] == -1) {
                pairUp(a, b);
                return true;
            }
            // Altfel, încercăm să "mutăm" împerecherea de la pj[b] dacă este posibil
            if(dfs(pj[b])) {
                pairUp(a, b);
                return true;
            }
        }
        return false;
    }

public:
    BipartiteMatcher(int n, int m, int e) : n(n), m(m), e(e) {
        g.resize(n);
        pi.assign(n, -1);
        pj.assign(m, -1);
    }

    // Citește și construiește lista de adiacență (nodurile 0..n-1 în stânga, 0..m-1 în dreapta)
    void readEdges() {
        for(int i = 0; i < e; i++){
            int a, b;
            cin >> a >> b;
            // trecem la indexare de la 0
            a--;
            b--;
            // adăugăm muchia în lista de adiacență
            g[a].push_back(b);
        }
    }

    // Rulează algoritmul de matching bipartit (Kuhn/DFS)
    int solve() {
        bool changed;
        do {
            changed = false;
            vis.assign(n, false);

            // Încercăm să extindem matchingul pentru fiecare nod din stânga care nu e încă împerecheat
            for(int i = 0; i < n; i++) {
                if(pi[i] == -1) {
                    if(dfs(i)) {
                        changed = true;
                    }
                }
            }
        } while(changed);

        // numărăm câte perechi s-au format
        int num = 0;
        for(int i = 0; i < n; i++) {
            if(pi[i] != -1) num++;
        }
        return num;
    }

    // Afișează matching-ul găsit
    void printResult() {
        cout << solve() << "\n";
        // După ce solve() a rulat, avem pi[] și pj[] populate
        for(int i = 0; i < n; i++){
            if(pi[i] != -1) {
                cout << i + 1 << " " << pi[i] + 1 << "\n";
            }
        }
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    // Deschidem fișierele conform cerinței
    freopen("cuplaj.in", "r", stdin);
    freopen("cuplaj.out", "w", stdout);

    int n, m, e;
    cin >> n >> m >> e;

    // Construim obiectul de matching bipartit
    BipartiteMatcher matcher(n, m, e);
    matcher.readEdges();

    // Afișăm rezultatul (dimensiunea matching-ului și perechile)
    matcher.printResult();

    return 0;
}