Cod sursa(job #2962691)

Utilizator alexdn6Dina Alexandru alexdn6 Data 8 ianuarie 2023 23:01:36
Problema Cuplaj maxim in graf bipartit Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.78 kb
#include <fstream>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
ifstream f ("cuplaj.in");
ofstream g ("cuplaj.out");

int n, m, cardL, cardR, fluxmaxim;
vector<vector<int>> graf(202, vector<int>(20000, 0));
vector<vector<int>> lista_ad;
vector<int> parinte;
vector<bool> vizitat;
queue <int> coada;

// Metoda de rezolvare este asemanatoare cu cea a "No prime sum" de pe csacademy sau "Harta" de pe IA
// Mai exact:
// - adaug un nod sursa
// - adaug un nod terminal
// - impart nodurile in 2 multimi (prima are cardL noduri, iar a doua cardR)
// - adaug muchii intre sursa si prima multime de noduri
// - adaug muchii intre nodurile din a doua multime si terminal
// - adaug flux pe muchii (1 peste tot)
// - intre nodurile din multimi diferite adaug muchii, tot cu fluxul 1
// Mai departe algoritmul este acelasi ca la FluxMaxim


bool bfs() {

    coada = queue <int> (); // golesc coada
    fill(vizitat.begin(), vizitat.end(), false);
    fill(parinte.begin(), parinte.end(), -1);

    coada.push(0);
    vizitat[0] = true;

    while (!coada.empty()) {
        int nod = coada.front();
        coada.pop();

        for (auto vec: lista_ad[nod]) {
            if (!vizitat[vec] && graf[nod][vec] > 0) {
                parinte[vec] = nod;
                coada.push(vec);
                vizitat[vec] = true;
            }
        }
    }

    return vizitat[n + 1];
}


void FluxMaxim() {
   
    while (bfs()) {

        for (auto vec: lista_ad[n + 1])
        {
            if (!(vizitat[vec] && graf[vec][n + 1] != 0))
                continue;

            int aux = vec, capacitateMaxima = 1;

            while (aux != 0) {
                if (graf[parinte[aux]][aux] == 0) {
                    capacitateMaxima = 0;
                    break;
                }
                aux = parinte[aux];
            }
            
            if (capacitateMaxima == 1) {
                aux = vec;

                graf[aux][n + 1] -= capacitateMaxima;
                graf[n + 1][aux] += capacitateMaxima;

                while (aux != 0) {
                    graf[parinte[aux]][aux] -= capacitateMaxima;
                    graf[aux][parinte[aux]] += capacitateMaxima;
                    aux = parinte[aux];
                }

                fluxmaxim += capacitateMaxima;
            }
        }
    }

    g << fluxmaxim << "\n";

// Parcurgem nodurile din prima multime
// Pentru fiecare vecin al fiecarui nod din prima multime
// Daca nu e sursa sau terminalul si daca capacitatatea ramasa pe muchia de la i la lista_ad[i][j] (vec) e 0, il afisam

    for (int i = 1; i <= cardL; i++)
        for (auto nod: lista_ad[i])
            if (graf[i][nod] == 0 && nod != 0 && nod != n + 1)
                g << i << " " << nod - cardL << "\n";
}

int main()
{
    f >> cardL >> cardR >> m;
    n = cardL + cardR;
    lista_ad.resize(n + 2);
    vizitat.resize(n + 2);
    parinte.resize(n + 2);
    graf = vector<vector<int>> (n + 2, vector<int>(n + 2, 0));


// - Adaug nodul sursa, il conectez la toate nodurile din prima multime
// si pun fluxul 1 pe fiecare muchie de la sursa la nod
    for (int u = 1; u <= cardL; u++) {
        graf[0][u] = 1;
        lista_ad[0].push_back(u);
        lista_ad[u].push_back(0);
    }

// -> Adaug nodul terminal, il conectez la toate nodurile din a doua multime
// si pun fluxul 1 pe fiecare muchie de la sursa la nod
    for (int u = cardL + 1; u <= n; u++) {
        graf[u][n + 1] = 1;
        lista_ad[n + 1].push_back(u);
        lista_ad[u].push_back(n + 1);
    }

// - Acum citesc cele e muchii si le pun in lista
    int u, v;
    for (int i = 0; i < m; i++) {
        f >> u >> v;
        graf[u][v + cardL] = 1;
        lista_ad[u].push_back(v + cardL); // adun n ca sa le pun in a doua multime
        lista_ad[v + cardL].push_back(u);
    }

    FluxMaxim();
    return 0;
}