Cod sursa(job #2963741)

Utilizator allee69Aldea Alexia allee69 Data 11 ianuarie 2023 22:57:46
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.92 kb
#include <bits/stdc++.h>
#define INF INT_MAX

using namespace std;

ifstream f("cuplaj.in");
ofstream g("cuplaj.out");

//algoritmul lui Hopcroft Karp O(sqrt(VE))
int n, m, e, a, b;
vector<int> v[20001];
queue<int> q;
int d[20001];
int st[20001], dr[20001];

bool BFS() {
    //in primul layer de noduri ii setam danta cu 0
    for (int i = 1; i <= n; i++)
        if (!dr[i]) //daca e liber,il bagam in coada
        {
            q.push(i);
            d[i] = 0;
        }
        else //notam distanta cu INFinit ca sa fie luat data urmatoare
            d[i] = INF;
        
    d[0] = INF; //q o sa aiba nodurile de stanga
    
    while (!q.empty())
    {
        int nod = q.front();
        q.pop();

        //daca nodul nu e 0 si poate aduce un short path catre 0
        if (d[nod] < d[0])//daca il cuplez pe 0 cu cineva => am gasit cuplaj din lant de lungime minima
        {
            //parcurgem toti vecinii lui nod
            for (auto next: v[nod]) {
                if (d[st[next]] == INF)//next e cuplat cu st[next]
                {
                    d[st[next]] = 1 + d[nod];
                    q.push(st[next]);
                }
            }
        }
    }
    return d[0] != INF; //lant
    // adevarat daca e un augmenting path incepand cu nodul liber nod
}

bool DFS(int nod)
{
    if(nod != 0)
    {
        for(auto next : v[nod])
            if(d[nod]+1  == d[st[next]] && DFS(st[next]))
            {
                st[next] = nod;
                dr[nod] = next;
                return true;
            }
        //nu am gasit path
        d[nod] = INF;
        return false;
    }
    return true;
}
int matchy()
{
    int ans = 0;
    while(BFS())
    {
        for(int i = 1 ; i <= n ; i++)
            if(!dr[i] && DFS(i))
                ans++;
    }
    return ans;
}
int main(){
    f >> n >> m >> e;
    fill(st, st + 20001, 0);
    fill(dr, dr + 20001, 0);
    for(int i = 1 ; i <= e ; i++)
    {
        f >> a >> b;
        v[a].push_back(b);
    }
    g << matchy() << '\n';
    for(int i = 1 ; i <= m ; i++)
        if(st[i])
            g << st[i] << ' ' << i << '\n';
    return 0;
}
//complexitate algoritm: O(sqrt(VE))

//codul de mai sus este o alta varianta de implementare a codului Ford-Fulkerson
//pentru a gasi cardinalitatea buna intr-un graf bipartit. Alg foloseste
//parcurgerea BFS pentru a gasi drumurile augmentate, iar parcurgerea
//DFS o foloseste pt a gasi drumul augmentat din ultimul vertex, gasit in
//BFS
//in vectorul v stocam nodurile, q e coada pt BFS, d -> distanta pt fiecare
//vertex, st si dr -> stanga si dreapta
// Functia matchy foloseste loopul while care functioneaza atat timp cat
//exista un drum augmentat in graf. In while, incepe un for prin care
//incepe cu un ciclu nevizitat, unmatched si fol DFS pentru a gasi drumul
//augmentat. Daca-l gaseste, il creste pe ans-> variabila care numara
//numarul de drumuri potrivite
//Functia main apeleaza functia matchy si afiseaza ce se cere in cerinta.