Cod sursa(job #2960594)

Utilizator woodyinhoStoica Elias-Valeriu woodyinho Data 4 ianuarie 2023 18:39:08
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.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<int> vizitat;
vector<int> tata;
vector<vector<int>> indice_muchii; //aici vom retine indicii acelor muchii din vectorul de muchii, al caror capat este nodul i
struct muchie
{
    int x, y, capacitate, poz; // ne ajuta aceasta structura sa retinem strict muchiile care sunt in graf
    //in schimb, daca faceam o matrice de capacitati de dimensiune n*m, atunci ar fi fost nevoie sa retinem si muchiile care nu sunt in graf
    //si depaseam memoria disponibila
};

vector<muchie> muchii;

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

int bfs(){
    tata.clear();
    tata.resize(n);
    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(int i : indice_muchii[nod]){
            muchie m_curent = muchii[i];
            if(!vizitat[m_curent.y] and m_curent.capacitate != 0){
                vizitat[m_curent.y] = 1;
                tata[m_curent.y] = i; //retinem muchia care ne duce la nodul m.y
                coada.push(m_curent.y);
            }
        }
    }
    return vizitat[dest];
}

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
    //in cazul in care nu mai exista drumuri, atunci nu mai avem ce sa mai cautam
    while(bfs()){
        for(auto i:indice_muchii[dest]){
            if(vizitat[muchii[i].y] and muchii[muchii[i].poz].capacitate != 0){
                //daca am gasit o muchie care duce la destinatie si care are capacitatea diferita de 0
                //atunci vom cauta drumul de la sursa la destinatie pe care il vom folosi pentru a afla fluxul maxim
                int flux = 1e9;
                muchie m_curent = muchii[i];
                tata[dest] = m_curent.poz;
                int nod = dest;
                while(nod != sursa){
                    flux = min(flux, muchii[tata[nod]].capacitate);
                    nod = muchii[tata[nod]].x;
                }
                nod = dest;
                while(nod != sursa){
                    //actualizam capacitatea muchiilor
                    muchii[tata[nod]].capacitate -= flux;
                    muchii[muchii[tata[nod]].poz].capacitate += flux;
                    nod = muchii[tata[nod]].x;
                }
                //actualizam fluxul maxim
                maxFlux += flux;
            }
        }
    }

    return maxFlux;
}

int main() {

    f>>l>>r>>m;
    n = l + r + 2;
    sursa = 0;
    dest = n - 1;
    vizitat.resize(n);
    tata.resize(n); //tata[i] = nodul din care am ajuns in nodul i
    indice_muchii.resize(n); //indice_muchii[i] = vectorul de indici ai muchiilor care pleaca din nodul i

    for(int i = 1; i <= m; i++){
        int x, y;
        f>>x>>y;
        muchii.push_back({x, y + l, 1, 2 * i - 1});
        muchii.push_back({y + l, x, 0, 2 * i - 2});
        indice_muchii[y + l].push_back(2 * i - 1);
        indice_muchii[x].push_back(2 * i - 2);
    }
    //adaugam un nod sursa care va fi nodul 0 si un nod destinatie care va fi nodul n - 1
    //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

    int dimensiune_muchii = int (muchii.size());
    for(int i = 1; i <= l; i++){
        //adaugam muchii de la sursa la nodurile din stanga
        dimensiune_muchii += 2;
        muchii.push_back({sursa, i, 1, dimensiune_muchii - 1});
        indice_muchii[i].push_back(dimensiune_muchii - 1);
        muchii.push_back({i, sursa, 0, dimensiune_muchii - 2});
        indice_muchii[sursa].push_back(dimensiune_muchii - 2);
    }

    for(int i = l + 1; i < n - 1; i++){
        //adaugam muchii de la nodurile din dreapta la destinatie
        dimensiune_muchii += 2;
        muchii.push_back({i, dest, 1, dimensiune_muchii - 1});
        indice_muchii[dest].push_back(dimensiune_muchii - 1);
        muchii.push_back({dest, i, 0, dimensiune_muchii - 2});
        indice_muchii[i].push_back(dimensiune_muchii - 2);

    }

//    //afisare muchii
//    for(muchie m : muchii){
//        cout<<m.x<<" "<<m.y<<" "<<m.capacitate<<" "<<m.poz<<endl;
//    }
//
//    //afisare indice_muchii
//    for(int i = 0; i < indice_muchii.size(); i++){
//        cout<<i<<": ";
//        for(int j : indice_muchii[i]){
//            cout<<j<<" ";
//        }
//        cout<<endl;
//    }

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

    //nodurile cuplate vor reprezenta arcele care fac parte din cuplajul maxim si au capacitatea 0 in matricea de capacitate
    //si care nu sunt adiacente cu nodul sursa sau destinatie

    for(auto & i : muchii){
        if(i.capacitate == 0 and i.x != sursa and i.y != dest and i.x < i.y){
            g<<i.x<<" "<<i.y - l<<"\n";
        }
    }

    return 0;
}