Cod sursa(job #3331821)

Utilizator GliggyGligor Andrei Gliggy Data 31 decembrie 2025 15:37:01
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.98 kb
#include <iostream>    // Librăria pentru fluxurile standard de intrare/ieșire
#include <vector>      // Librăria pentru vectori (liste dinamice)
#include <queue>       // Librăria pentru structura de date de tip coadă (folosită la BFS)
#include <fstream>     // Librăria pentru lucrul cu fișiere

using namespace std;   // Permite utilizarea funcțiilor standard fără prefixul std::

const int MAXN = 10005; // Definim dimensiunea maximă pentru noduri conform restricțiilor
const int INF = 1e9;    // Definim o valoare foarte mare pentru distanțe (infinit)

ifstream fin("cuplaj.in");   // Deschidem fișierul de intrare
ofstream fout("cuplaj.out"); // Deschidem fișierul de ieșire

vector<int> adj[MAXN];      // Lista de adiacență pentru a stoca muchiile dintre mulțimile A și B
int perecheA[MAXN];         // perecheA[u] stochează nodul din B cu care este cuplat u din A
int perecheB[MAXN];         // perecheB[v] stochează nodul din A cu care este cuplat v din B
int dist[MAXN];             // Stochează nivelul (stratul) fiecărui nod calculat de BFS
int n, m, e;                // n - noduri în A, m - noduri în B, e - numărul de muchii

// Funcția BFS: Împarte graful în straturi pentru a găsi cele mai scurte drumuri de creștere
bool bfs() {
    queue<int> q;           // Creăm o coadă pentru parcurgerea în lățime
    for (int i = 1; i <= n; i++) { // Parcurgem toate nodurile din mulțimea A
        if (perecheA[i] == 0) {    // Dacă nodul i este liber (necuplat)
            dist[i] = 0;           // Începe un nou drum de creștere (nivelul 0)
            q.push(i);             // Îl adăugăm în coadă pentru procesare
        } else {
            dist[i] = INF;         // Dacă e deja cuplat, îl marcam cu infinit (nevizitat)
        }
    }

    dist[0] = INF; // Nodul 0 este un nod virtual care reprezintă "capătul" unui drum de creștere

    while (!q.empty()) {           // Cât timp mai avem noduri în coadă
        int u = q.front();         // Luăm primul nod din coadă
        q.pop();                   // Îl eliminăm din coadă

        if (dist[u] < dist[0]) {   // Dacă nu am depășit nivelul primului drum de creștere găsit
            for (int v : adj[u]) { // Analizăm toți vecinii nodului u din mulțimea B
                // Verificăm dacă partenerul lui v (care e în A) nu a fost vizitat
                if (dist[perecheB[v]] == INF) {
                    dist[perecheB[v]] = dist[u] + 1; // Setăm stratul următor
                    q.push(perecheB[v]);             // Adăugăm partenerul în coadă
                }
            }
        }
    }
    
    // Returnează true dacă am reușit să ajungem la nodul virtual 0 (un nod liber din B)
    return (dist[0] != INF);
}

// Funcția DFS: Caută drumuri de creștere pe straturile definite de BFS
bool dfs(int u) {
    if (u != 0) { // Dacă nodul curent nu este nodul virtual de final
        for (int v : adj[u]) { // Parcurgem vecinii nodului u
            // Verificăm dacă vecinul face parte din stratul imediat următor
            if (dist[perecheB[v]] == dist[u] + 1) {
                if (dfs(perecheB[v])) { // Încercăm să găsim un drum de creștere recursiv
                    perecheB[v] = u;    // Dacă s-a găsit, actualizăm cuplajul pentru v
                    perecheA[u] = v;    // Actualizăm cuplajul pentru u
                    return true;        // Confirmăm că drumul a fost găsit
                }
            }
        }
        dist[u] = INF; // Dacă nu există drum prin u, îl marcăm pentru a nu-l mai vizita
        return false;  // Nu am găsit drum de creștere prin acest nod
    }
    return true; // Am ajuns la nodul virtual 0, drumul de creștere este complet
}

int main() {
    if (!(fin >> n >> m >> e)) return 0; // Citim dimensiunile și verificăm dacă s-a reușit

    for (int i = 0; i < e; i++) { // Citim cele e muchii ale grafului
        int u, v;                 // Variabile pentru nodurile ce formează muchia
        fin >> u >> v;            // Citim nodul u din A și nodul v din B
        adj[u].push_back(v);      // Adăugăm v în lista de adiacență a lui u
    }

    int cuplaj_maxim = 0;         // Variabilă pentru a număra câte perechi am format
    
    // Rulăm algoritmul în faze: BFS construiește straturi, DFS caută drumuri în ele
    while (bfs()) {               // Cât timp BFS găsește drumuri de creștere posibile
        for (int i = 1; i <= n; i++) { // Pentru fiecare nod din mulțimea A
            // Dacă nodul este liber și DFS reușește să îi găsească o pereche
            if (perecheA[i] == 0 && dfs(i)) {
                cuplaj_maxim++;   // Incrementăm mărimea totală a cuplajului
            }
        }
    }

    fout << cuplaj_maxim << "\n"; // Afișăm numărul maxim de perechi formate
    for (int i = 1; i <= n; i++) { // Parcurgem nodurile din prima mulțime
        if (perecheA[i] != 0) {    // Dacă nodul i a fost cuplat
            fout << i << " " << perecheA[i] << "\n"; // Afișăm perechea (A, B)
        }
    }

    return 0; // Finalizăm programul
}
// // Copilot Rules:
// // RULE: There shouldnt be any spaces in the code, except after commas.
// // RULE: All variables in main should be declared globally, and can be used before they are defined.
// // RULE: All open curly braces should be placed on the same line as the function or control structure they belong to, not on the line after.
// #include <bits/stdc++.h>
// #define N 10010
// using namespace std;
// ifstream fin("cuplaj.in");   //strudel
// ofstream fout("cuplaj.out"); //cuplaj
// int n,m,e,i,x,y,cnt,inf=1e9;
// vector<int> v[N];
// int pda[N],pdb[N],lvl[N];
// queue<int> q;
// bool bfs(){
//     while(!q.empty()) q.pop();
//     for(i=1;i<=n;i++){
//         if(pdb[i]==0) lvl[i]=0,q.push(i);
//         else lvl[i]=inf;
//     }
//     lvl[0]=inf;
//     while(!q.empty()){
//         int u=q.front();
//         q.pop();
//         if(lvl[u]<lvl[0])
//             for(auto vec:v[u]){
//                 if(lvl[pda[vec]]==inf){
//                     lvl[pda[vec]]=lvl[u]+1;
//                     q.push(pda[vec]);
//                 }
//             }
//     }
//     return lvl[0]!=inf;
// }
// bool dfs(int nod){
//     if(nod==0) return 1;
//     for(auto vec:v[nod]){
//         if(lvl[pda[vec]]==lvl[nod]+1&&dfs(pda[vec])==1){
//             pda[vec]=nod,pdb[nod]=vec;
//             return 1;
//         }
//     }
//     lvl[nod]=inf;
//     return 0;
// }
// int main()
// {
//     fin>>n>>m>>e;
//     for(i=1;i<=e;i++){
//         fin>>x>>y;
//         v[x].push_back(y);
//     }
//     while(bfs()==1){
//         for(i=1;i<=n;i++){
//             if(pdb[i]==0&&dfs(i)==1){
//                 cnt++;
//                 break;
//             }
//         }
//     }
//     fout<<cnt<<'\n';
//     for(i=1;i<=n;i++)
//         if(pdb[i]!=0) fout<<i<<" "<<pdb[i]<<'\n';
//     return 0;
// }