Cod sursa(job #806825)

Utilizator danalex97Dan H Alexandru danalex97 Data 3 noiembrie 2012 16:24:29
Problema Cuplaj maxim in graf bipartit Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 3.36 kb
// Cuplaj in graf bipartit cu liste alternante
// Solutia este un greedy care cupleaza un nod cu
// primul necuplat din cealalta multime si in cazul
// in care nu avem cu cine sa cuplam nodul actual
// vom incerca sa decuplam pe rand fiecare pereche din
// cealalta parte. Deci vom cauta pe rand la fiecare nod
// Toate posibilitatile de emergenta de mai sus , astfel
// vom avea de parcurs cel mult L muchii , deci L pasi
// pentru fiecare N muchii. Deci O(N*L) supraestimat.

// O alta abordarea a cuplajului maxim este tratarea acestuia
// ca o retea cu flux si folosirea algoritmilor de flux maxim.
// O rezolvare cu retinerea arborelui BFS cu parinti si cu
// parcurgerea unui numar maxim de drumuri la un pas aduce o
// complexitate de flux in retea. Comeplexitate daca implementam
// dupa cele de mai sus este O(N*sqrt(V)) , numarul de pasi fiind
// maxim sqrt(V) , acesta numindu-se algritmul lui Hopcroft Karp.
// Reteaua de flux va porni din nodul s care va avea muschii la
// fiecare nod din prima multime si se va termina la nodul t care
// va fi legat la fiecare nod din a 2-a multime.

// Metoda 1 in sine merge pe un drum in sus de lungime cel mult L.
// Deci la fiecare pas incerc sa cuplez nodul actual cu unul nou ,
// iar daca nu reusesc incerc sa recuplez fiecare nod de mai sus
// cu altul decat cel acutal. Daca nici un nod de mai sus nu are gradul
// mai mare ca 0 cuplajul ramane acelasi. In caz contrar se schimba.
// Datorita faptului ca legaturile sunt deja notate in L si R nici un
// nod nu va schimba legaturile decat daca poate. Daca poate sa schimbe
// un nod legaturile le vor schimba si restul nodruilor din parcurgere.

#include <fstream>
#include <vector>
#include <cstring>
using namespace std;

ifstream F("cuplaj.in");
ofstream G("cuplaj.out");

const int Nmax = 10010;

vector<int> A[Nmax];
int Fixed[Nmax];
int L[Nmax],R[Nmax];
int N,M,T,Sol;

typedef vector<int>::iterator IT;

int Look( int Nod )
{
    if ( Fixed[Nod] == 1 ) return 0; // deca legatura e fixata iesim
    Fixed[Nod] = 1; // fixam nodul

    for (IT it=A[Nod].begin();it!=A[Nod].end();++it)
    // ma uit daca vreun nod direct e necuplat
        if ( R[*it] == 0 )
        {
            L[ Nod ] = *it;
            R[ *it ] = Nod;
            return 1;
        }
    for (IT it=A[Nod].begin();it!=A[Nod].end();++it)
    // daca nu a fost nici un nod necuplat ma uit la un posibil cuplaj anterior
        if ( Look( R[*it] ) )
        {
            L[ Nod ] = *it;
            R[ *it ] = Nod;
            return 1;
        }

    return 0; // asta se intampla daca nu am reusit sa facem nici o legatura
}

int main()
{
    F>>N>>M>>T;
    for (int i=1,x,y;i<=T;++i)
    {
        F>>x>>y;
        A[x].push_back(y);
    }

    for (int i=1;i<=N;++i)
        if ( L[i] == 0 ) // daca nodul actual nu e cuplat il cuplez
        {
            if ( !Look(i) ) // daca nu pot sa il cuplez
            {
                memset(Fixed, 0, sizeof(Fixed)); // nici o legatura anterioara nu e fixata
                // in cel mai rau caz voi ramane la numarul actual de legaturi , o legatura
                // veche fiind inlocuita cu aceasta noua
                Sol += Look(i);
            }
            else
                ++Sol;
        }
    G<<Sol<<'\n';
    for (int i=1;i<=N;++i)
        if ( L[i] )
            G<<i<<' '<<L[i]<<'\n';
}