Cod sursa(job #2960382)

Utilizator Nicolae11Mihaila Nicolae Nicolae11 Data 4 ianuarie 2023 11:32:30
Problema Cuplaj maxim in graf bipartit Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.56 kb
/*
    Ideea de rezolvare a algoritmului este urmatoarea:
    Folosim algoritmul de Max Flow. In plus, folosim optimizarea mentionata pe infoarena: La fiecare pas construim arborele BFS (excluzand destinatia),
si acum un drum de la sursa la destinatie e reprezentat de un drum de la sursa (care este radacina arborelui) la o frunza legata de destinatie printr-o
muchie nesaturata. Astfel putem la un pas sa marim fluxul pe un numar maximal de astfel de drumuri, fara a mai reface BFS-ul. Aceasta optimizare
reduce destul de mult timpul de executie.
    Fie cele doua multimi de noduri ale grafului bipartit impartite in doua multimi: grup1 si grup2.
    Acum vine partea de cuplaj: Adaugam doua noduri, sursa = s cu indicele 0 si destinatia = t cu indicele (grup1+grup2+1). Nodul s se conecteaza la
toate nodurile din grup1 printr-o muchie de capacitate 1, iar toate nodurile din grup2 se conecteaza la t printr-o muchie de capacitate 1. Aplicam
algoritmul de max flow. Fluxul maxim este egal cu numarul maxim de cuplaje realizabile. Potrivirile dintre nodurile din grup1 si grup2 vor fi
identificate prin muchiile care respecta o anumita proprietate.

Complexitate:
Fie n = numarul de noduri, m = numarul de muchii
Timp: O(n*m^2) ///totusi, avem optimizarea cu arborele BFS
Memorie: O(n+m) ///array de vizitati pentru noduri + listele de adiacenta
*/
#include <bits/stdc++.h> ///E belea mare la cum am declarat n. Vezi in for-uri si while-uri si altele cum accesam corect.
using namespace std;
ifstream f("cuplaj.in");
ofstream g("cuplaj.out");
int n,m,s,t;
int viz[10005];
int parinte[10005];
struct muchie
{
    int cap1;
    int cap2;
    int capacit;
    int pos;
};
vector<vector<int>> liste;
vector<muchie> muchii;
long long flux_maxim;
void AddMuchie(int x, int y, int c)
{
    muchie aux;
    int elem=(int)muchii.size();

    liste[y].push_back(elem+1);
    aux.cap1=x;
    aux.cap2=y;
    aux.capacit=1;
    aux.pos=elem+1;
    muchii.push_back(aux);

    liste[x].push_back(elem);
    aux.cap1=y;
    aux.cap2=x;
    aux.capacit=0;
    aux.pos=elem;
    muchii.push_back(aux);
}
bool bfs()
{
    memset(viz,0,sizeof(viz));
    memset(parinte,0,sizeof(parinte));
    queue <int> q;
    viz[0]=1;
    q.push(0);
    while(!q.empty())
    {
        int act=q.front();
        q.pop();
        if(act!=t)
            for(auto i : liste[act]) ///ne uitam prin vecinii nodului actual
            {   muchie aux_muc=muchii[i];
                if(viz[aux_muc.cap2]==0 && aux_muc.capacit>0) ///nodul nu e vizitat, iar muchia (fie ea din graful rezidual sau nu) mai accepta flux
                {
                    viz[aux_muc.cap2]=1;
                    parinte[aux_muc.cap2]=i;
                    q.push(aux_muc.cap2);
                }
            }
    }
    return viz[t];
}
int maxFlow()
{
    while(bfs()) ///cat timp mai exista drumuri nesaturate de la s la t
    {
        for(auto i : liste[t])
        {   if(viz[muchii[i].cap2]!=0 && muchii[muchii[i].pos].capacit>0)
            {
                int aux_flux=1000000; ///facem asta ca sa luam minimul de pe drum
                muchie aux_muc=muchii[i];
                parinte[t]=aux_muc.pos;
                int j=t;
                while(j!=0) ///calatorim din tata in tata pana ajungem la s si vedem cat flux putem baga pe drumul ala (bottleneck inclus)
                {
                    aux_flux=min(aux_flux,muchii[parinte[j]].capacit);
                    j=muchii[parinte[j]].cap1;
                }
                j=t;
                while(j!=0) ///mergem din tata in tata si modificam muchiile pe graful normal + cel rezidual
                {
                    muchii[parinte[j]].capacit-=aux_flux;
                    muchii[muchii[parinte[j]].pos].capacit+=aux_flux;
                    j=muchii[parinte[j]].cap1;
                }
                flux_maxim=flux_maxim+aux_flux; ///adaugam la flux_maxim fluxul pe care il avem pe drumul calculat
            }
        }
    }
    return flux_maxim;
}
int main()
{

    int grup1,grup2;
    f>>grup1>>grup2>>m;
    n=grup1+grup2+2;
    liste.resize(n);
    s=0;
    t=n-1;
    int x,y;
    for(int i=1;i<=m;i++)
    {
        f>>x>>y;
        AddMuchie(x,y+grup1,1);
    }
    for(int i=1;i<=grup1;i++)
        AddMuchie(s,i,1);
    for(int i=grup1+1;i<=grup1+grup2;i++)
        AddMuchie(i,t,1);
    m=m+grup1+grup2;
    g<<maxFlow()<<'\n';
    for(muchie i : muchii)
        if(i.cap1<i.cap2 && i.cap1!=0 && i.cap2!=t && i.capacit==0)
            g<<i.cap1<<' '<<i.cap2-grup1<<'\n';
    return 0;
}