Cod sursa(job #2960517)

Utilizator woodyinhoStoica Elias-Valeriu woodyinho Data 4 ianuarie 2023 15:59:32
Problema Cuplaj maxim in graf bipartit Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.21 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <string>

using namespace std;

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

vector<vector<int>> graf;
vector<int> vizitat;
vector<int> tata;
vector<vector<int>> capacitate;
vector<vector<int>> flux;

int n, m, sursa, dest, l, r;

void bfs(){
    fill(vizitat.begin(), vizitat.end(), 0);
    queue<int> coada;
    coada.push(sursa);
    vizitat[sursa] = 1;

    while(!coada.empty()){
        int nod = coada.front();
        coada.pop();
        if(nod == dest)
            continue;
        for(auto &vecin:graf[nod]){
            if(capacitate[nod][vecin] == flux[nod][vecin] || vizitat[vecin] == 1)
                continue;
            vizitat[vecin] = 1;
            tata[vecin] = nod;
            coada.push(vecin);
        }
    }
}

int fluxMaxim(){
    int maxFlux = 0;
    //facem bfs cat timp mai exista drumuri de la sursa la destinatie pe care sa le verificam pentru fluxul maxim
    bfs();
    //cout<<"dupa bfs";
    while(vizitat[dest] == 1){
        //daca am ajuns la destinatie, inseamna ca am gasit un nou drum si verificam fluxul maxim pe acest drum
        for(auto vecin: graf[dest]){
            if(capacitate[vecin][dest] == flux[vecin][dest]) //daca nu mai am capacitate pe muchia respectiva, nu o mai verific
                continue;
            tata[dest] = vecin;

            //memoram cat mai putem sa adaugam pe acest drum
            //sunt sanse ca din cauza ordinei in care am luat drumurile, unul din drumuri sa nu ajunga la capacitatea maxima, fiind
            //blocat de un alt drum
            int minim = capacitate[tata[dest]][dest] - flux[tata[dest]][dest];
            vecin = tata[dest];
            while(vecin != sursa){
                minim = min(capacitate[tata[vecin]][vecin] - flux[tata[vecin]][vecin], minim);
                vecin = tata[vecin];
            }

            //la final avem in minim cat mai putem sa adaugam pe acest drum
            vecin = dest;
            while(vecin != sursa){
                //adaugam
                flux[tata[vecin]][vecin] += minim;
                flux[vecin][tata[vecin]] -= minim;
                vecin = tata[vecin];
            }

            maxFlux += minim;

        }
        bfs();
        //cout<<"dupa alt bfs\n";
        //cout<<maxFlux;
        //cout<<"\n";
    }
    return maxFlux;
}

int main() {

    f>>l>>r>>m;
    n = l + r;
    sursa = 1;
    dest = n + 2;
    graf.resize(n + 3);
    vizitat.resize(n+3);
    tata.resize(n+3); //tata[i] = nodul din care am ajuns in nodul i
    capacitate.resize(n+3, vector<int>(n+3)); //capacitatea maxima a muchiei (i,j)
    flux.resize(n+3, vector<int>(n+3)); //fluxul propriu-zis de la i la j

    for(int i = 1; i <= m; i++){
        int x, y;
        f>>x>>y;
        graf[x + 1].push_back(y + l + 1);
        graf[y + l + 1].push_back(x + 1);
        capacitate[x + 1][y + l + 1] = 1;
    }
    //adaugam un nod sursa care va fi nodul 1 si un nod destinatie care va fi nodul n+2
    //facem muchii de la sursa la fiecare nod din stanga si de la fiecare nod din dreapta la destinatie
    //capacitatea maxima a acestor muchii va fi 1
    //reducem problema determinarii unui cuplaj maxim intr un graf bipartit la problema
    //determinarii unui flux maxim intr-o retea de transport asociata acelui graf bipartit si cu adaugarea
    //nodurilor sursa si destinatie

    for(int i = 2; i <= l + 1; i++){
        graf[sursa].push_back(i);
        graf[i].push_back(sursa);
        capacitate[sursa][i] = 1;
    }

    for(int i = l + 2; i <= n + 1; i++){
        graf[i].push_back(dest);
        graf[dest].push_back(i);
        capacitate[i][dest] = 1;
    }

    //afisare matrice de capacitate
//    for(int i = 1; i <= dest; i++){
//        for(int j = 1; j <= dest; j++){
//            cout<<capacitate[i][j]<<" ";
//        }
//        cout<<endl;
//    }

    g<<fluxMaxim()<<"\n";

    //nodurile cuplate vor reprezenta arcele cu flux nenul care nu sunt incidente nici cu sursa nici cu destinatia
    //afisam nodurile cuplate

    for(int i = 2; i <= l + 1; i++){
        for(auto vecin: graf[i]){
            if(flux[i][vecin] == 1){
                g<<i - 1<<" "<<vecin - l - 1<<"\n";
            }
        }
    }
    return 0;
}