Cod sursa(job #2962154)

Utilizator razvan1234Danciu Razvan razvan1234 Data 7 ianuarie 2023 20:59:16
Problema Cuplaj maxim in graf bipartit Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.11 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <iomanip>
#include <climits>
#include <queue>

using namespace std;

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

int n, m1, m2, m;
vector<vector<int>> lista_adiacenta; //lista de adiacenta a grafului
vector<vector<int>> graf_rezid; //pentru a retine capacitatea folosita intr-un anumit moment pentru o muchie

vector<int> vizit;
vector<int> tata;

bool BFS()
{
    queue<int> vecini;

    tata.clear();
    tata.resize(n+1, 0);

    vizit.clear();
    vizit.resize(n+1, 0);

    vecini.push(1);
    vizit[1] = 1;

    while(!vecini.empty()){
        int nod_curent = vecini.front();
        vecini.pop();

        if (nod_curent == n) break; //am ajuns la final

        for (auto it: lista_adiacenta[nod_curent]){
            if (!vizit[it] and graf_rezid[nod_curent][it] > 0){ //daca nu am trecut prin acel nod si capacitatea sa imi permite sa trec, atunci ma duc
                tata[it] = nod_curent; //ca sa retin drumul facut
                vecini.push(it);
                vizit[it] = 1;
            }
        }
    }
    return vizit[n]; //vizit[n] va fi true doar daca pot ajunge de la nodul 1 la nodul n
}


void DFS(int nod_inceput, vector<bool> &visited)
{
    visited[nod_inceput] = 1;

    for (auto it: graf_rezid[nod_inceput]){
        if (graf_rezid[nod_inceput][it] and !visited[it])
            DFS(it, visited);
    }
}


void getNrCuplaj()
{
    int nr = 0;
    for (int i = 1; i <= m1; i++){
        if (!graf_rezid[1][i * 2]) nr++;
    }
    fout << nr << endl;
}


int findVecin(int nod)
{
    for (int i = 1; i <= m2; i++){
        if (!graf_rezid[nod][i * 2 + 1]) return i;
    }
}

void findCuplaj()
{
    getNrCuplaj();

    for (int i = 1; i <= m1; i++){
        if (!graf_rezid[1][i * 2]){
            int vecin = findVecin(i * 2);
            fout << i  << " " << vecin << endl;
        }
    }
}


void EdmondsKarp()
{
    int flux_max = 0;
    while (BFS()){ //cat timp am drum de la sursa pana la final
        for (auto it: lista_adiacenta[n]){ //iau vecinii nodului final
            if (vizit[it] and graf_rezid[it][n] > 0){
                int flux_curent = graf_rezid[it][n]; ///pornesc cu fluxul egal cu capacitatea vecinului lui n
                for (int i = it; i != 1; i = tata[i]){ ///parcurg drumul spre nodul 1
                    flux_curent = min(flux_curent, graf_rezid[tata[i]][i]); //actualizez fluxul in functie de capacitatea nodurilor pe care le intalnesc in drumul meu
                }

                //actualizez graful rezidual
                graf_rezid[it][n] -= flux_curent;
                graf_rezid[n][it] += flux_curent;

                for (int i = it; i != 1; i = tata[i]){
                    graf_rezid[tata[i]][i] -= flux_curent;
                    graf_rezid[i][tata[i]] += flux_curent;
                }

                //adaug fluxul curent la cel maxim
                flux_max += flux_curent;
            }
        }
    }

    findCuplaj();

}

int main()
{
   fin >> m1 >> m2 >> m;

   //stabilesc nodul final
   if (m1 > m2) n = m1 * 2 + 1;
   else n = m2 * 2 + 2;

   lista_adiacenta.resize(n+1);
   graf_rezid.resize(n+1, vector<int>(n+1, -1));

   for (int i = 1; i <= m; i++){
       int x, y, z;
       fin >> x >> y;

       //reprezint nodurile din prima multime ca fiind noduri pare in reteaua de transport asociata
       //reprezint nodurile din a doua multime ca fiind noduri impare in reteaua de transport asociata
       x *= 2;
       y = y * 2 + 1;

       lista_adiacenta[x].push_back(y);
       lista_adiacenta[y].push_back(x); //pentru arcele inverse
       graf_rezid[x][y] = 1; //retin capacitatea
   }

   //adaug arcele de la nodul sursa la fiecare din nodurile din prima multime
   for (int i = 1; i <= m1; i++){
       lista_adiacenta[1].push_back(i * 2);
       lista_adiacenta[i * 2].push_back(1);
       graf_rezid[1][i * 2] = 1;
   }
   //adaug arcele de la nodurile din a doua multime la nodul final
   for (int i = 1; i <= m2; i++){
       lista_adiacenta[i * 2 + 1].push_back(n);
       lista_adiacenta[n].push_back(i * 2 + 1);
       graf_rezid[i * 2 + 1][n] = 1;
   }

   EdmondsKarp();
}