Cod sursa(job #2967172)

Utilizator maria-marianita.cucos@s.unibuc.roCucos Marianita [email protected] Data 19 ianuarie 2023 10:08:26
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 8.9 kb
// Complexitate: O(n * m^2), unde n = nr. noduri, m = nr. muchii

#include <bits/stdc++.h>
using namespace std;

ifstream fin("cuplaj.in");
ofstream fout("cuplaj.out");

int sizeLeft; // nr. de noduri din partea stanga a grafului bipartit
int sizeRight; // nr. de noduri din partea dreapta a grafului bipartit
int edges; // nr. total de muchii
int source, sink; // nodurile sursa si destinatie

vector <pair <int, int>> parent; // perechi de tip <nod, indexul muchiei> care retin nodul din care s-a ajuns la nodul curent si indexul muchiei care a fost folosita
vector <pair <int, int >> sinkEdges; // perechi de tip <nod, indexul muchiei> care reprezinta muchiile care conecteaza nodurile din dreapta grafului cu nodul destinatie
vector <vector <pair <int, pair <int, int> >>> adjList; // perechi de tip <nod, <capacitate, indexul muchiei catre nodul vecin>> care reprezinta muchiile grafului
vector <bool> rightNodes; // vector pentru a retine nodurile din dreapta grafului bipartit conectate la cel putin un nod din partea stanga


void createEdge(int x, int y) {
    // muchie de la nodul x la nodul y cu capacitate 1 si indexul muchiei
    adjList[x].push_back({y, {1,adjList[y].size()}});

    // muchie de la nodul y la nodul x cu capacitate 0 si indexul muchiei
    adjList[y].push_back({x, {0,adjList[x].size() - 1}});

    // daca nodul y este nodul destinatie, adaugam muchia la lista de muchii care conecteaza nodurile din partea dreapta a grafului bipartit la nodul destinatie
    if (y == sink) {
        sinkEdges.push_back(make_pair(x, adjList[x].size() - 1));
    }
}



// Functie care face BFS pe graf si returneaza true / false daca exista sau nu drum de la sursa la destinatie
bool bfs() {
    vector <bool> visited(sink + 1);
    queue <int> q;

    q.push(source);
    visited[source] = true;
    parent[source] = {-1, -1};

    while (!q.empty()) {
        int firstInQueue = q.front();
        q.pop();

        if (firstInQueue == sink) {
            return true;
        }

        int edgeIndex = 0;

        for (auto const& neighbor : adjList[firstInQueue]) {
            int node = neighbor.first; // nodul vecin
            int capacity = neighbor.second.first; // capacitatea muchiei


            if (!visited[node] && capacity) {
                parent[node] = {firstInQueue, edgeIndex};
                visited[node] = true;
                q.push(node);
            } // daca vecinul n-a fost vizitat si exista capacitate pe muchie, se seteaza parintele nodului vecin si indexul muchiei curente, apoi acesta se adauga in coada

            ++edgeIndex;
        }
    }

    return visited[sink];
}



int Edmonds_Karp() {
    int maxFlow = 0;

    while (bfs()) {
        for (auto const& neighbor : sinkEdges) {  // se parcurge lista de muchii care conecteaza nodurile din partea dreapta a grafului bipartit la nodul destinatie
            int currentFlow = 1;
            parent[sink] = neighbor; // se seteaza parintele nodului destinatie la nodul curent

            int y = sink;
            while (parent[y].first != -1) { // se parcurge invers drumul de la nodul destinatie la sursa folosindu-ne de parintele fiecarui nod

                int x = parent[y].first;
                int i = parent[y].second;

                currentFlow = min(currentFlow, adjList[x][i].second.first); // se calculeaza fluxul curent ca fiind minimul dintre fluxul curent si capacitatea muchiei
                y = x;
            }

            // se actualizeaza fluxul pe muchii, parcurgand din nou drumul de la nodul destinatie la sursa
            y = sink;
            while (parent[y].first != -1) {
                int a = parent[y].first;
                int b = parent[y].second;
                int c = adjList[a][b].second.second;

                adjList[a][b].second.first -= currentFlow;
                adjList[y][c].second.first += currentFlow;

                y = a;
            }

            maxFlow += currentFlow;
        }
    }

    return maxFlow;
}



int main() {
    fin >> sizeLeft >> sizeRight >> edges;

    // source = 0;
    sink = sizeLeft + sizeRight + 1;

    parent.resize(sink + 1);
    adjList.resize(sink + 1);
    rightNodes.resize(sizeRight + 1);

    for (int i = 1; i <= sizeLeft; ++i) {
        createEdge(source, i); // legam nodul sursa 0 de toate nodurile din partea stanga a grafului bipartit
    }

    for (int i = 1; i <= edges; ++i) {
        int x, y;
        fin >> x >> y;
        createEdge(x, sizeLeft + y); // legam nodurile din partea stanga a grafului bipartit cu nodurile din partea dreapta a grafului bipartit
        rightNodes[y] = true;
    }

    for (int i = 1; i <= sizeRight; ++i) {
        if (rightNodes[i]) {
            createEdge(sizeLeft + i, sink); // legam nodurile din partea dreapta a grafului bipartit cu nodul destinatie
        }
    }


    fout << Edmonds_Karp();

    // pentru fiecare nod din partea stanga a grafului bipartit cautam nodul din dreapta la care este conectat
    for (int node = 1; node <= sizeLeft; ++node) {
        for (auto const &neighbor : adjList[node]) {
            int vertex = neighbor.first;
            int capacity = neighbor.second.first;

            if (vertex && capacity == 0 && vertex != sink) { // daca nodul vecin nu este nodul sursa / destinatie si capacitatea muchiei este 0, inseamna ca nodul curent este conectat la nodul vecin
                fout << '\n' << node << " " << vertex - sizeLeft;
            }
        }
    }

    fin.close();
    fout.close();
    return 0;
}




//// cuplaj maxim cu flux
//// val(f) = |M|
//// complexitate: O(mn)
//
//
//#include <iostream>
//#include <fstream>
//#include <vector>
//#include <queue>
//using namespace std;
//
//struct muchie{
//    int start,end,cp,ind; // nod1, nod2, capacitate, indice
//};
//int noduri;
//int n,m,e;
//int sursa, destinatie;
//vector<muchie> muchii;
//vector<vector<int>> adj_list;
//vector<int> parinti; // pt nodul x retinem indicele muchiei cu care s-a ajuns la x
//vector<bool> viz;
//
//void adauga_muchie(int a, int b){
//    int dim = (int)muchii.size();
//
//    adj_list[a].push_back(dim);
//    adj_list[b].push_back(dim + 1);
//
//    muchii.push_back({a,b, 1,  dim + 1});
//    muchii.push_back({b,a, 0,  dim});
//
//}
//
//bool gaseste_drum(){
//    viz.clear();
//    parinti.clear();
//    viz.resize(noduri, false);
//    parinti.resize(noduri);
//
//    queue<int> q;
//    viz[sursa] = true;
//    q.push(sursa);
//    while(!q.empty()){
//        int node = q.front();
//        q.pop();
//        if(node != destinatie){
//            for(int x : adj_list[node]){ // x este indicele muchiei
//                muchie curr_m = muchii[x];
//                if(!viz[curr_m.end] and curr_m.cp != 0){
//                    parinti[curr_m.end] = x;
//                    q.push(curr_m.end);
//                    viz[curr_m.end] = true;
//                }
//            }
//        }
//    }
//    return viz[destinatie];
//}
//
//int main() {
//    ifstream fin("cuplaj.in");
//    ofstream fout("cuplaj.out");
//    fin >> n >> m >> e;
//
//    noduri = m + n + 2;
//    sursa  = 0;
//    destinatie = n + m + 1;
//    adj_list.resize(noduri);
//    while(e--){
//        int x,y;
//        fin >> x >> y;
//        adauga_muchie(x, y + n);
//    }
//
//    for(int i = 1;i <= n; ++i){
//        adauga_muchie(sursa,i);
//    }
//    for(int j = n + 1; j <= n + m; ++j) {
//        adauga_muchie(j,destinatie);
//    }
//
//    int ans = 0;
//    while(gaseste_drum()){ // daca s-a ajuns de la sursa la destinatie
//        for(int x : adj_list[destinatie]){ //parcurg invers
//            if(viz[muchii[x].end] and muchii[muchii[x].ind].cp != 0){ //daca s-a ajuns cu muchia respectiva in T
//                //muchie reziduala                                      // si daca capacitatea nu e 0
//                muchie curr_m = muchii[x];
//                //indicele muchiei din graf
//                parinti[destinatie] = curr_m.ind;
//                int flux = 99999999;
//                int node = destinatie;
//                while(node != sursa){ //flux min
//                    flux = min(flux,muchii[parinti[node]].cp);
//                    node = muchii[parinti[node]].start;
//                }
//
//                node = destinatie;
//                while(node != sursa){
//                    muchii[parinti[node]].cp -= flux;
//                    muchii[muchii[parinti[node]].ind].cp += flux;
//                    node = muchii[parinti[node]].start;
//                }
//                ans += flux;
//            }
//        }
//    }
//    fout << ans <<"\n";
//    for(auto x: muchii){
//        if(x.start < x.end and x.start != sursa and x.end != destinatie and x.cp == 0){
//            fout << x.start << " " << x.end-n <<"\n";
//        }
//    }
//    return 0;
//}