Cod sursa(job #2961360)

Utilizator TindecheTindeche Alexandru Tindeche Data 6 ianuarie 2023 12:45:22
Problema Cuplaj maxim in graf bipartit Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.28 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <climits>
#include <stack>
#include <unordered_map>

using namespace std;

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

/*
 * Algoritmul este prezentat in curs. Pasii sunt urmatorii:
 * 1. Se adauga o sursa si un destinatie fictive
 * 2. Se adauga muchiile de la sursa si destinatie la cele doua multimi de noduri
 * 3. Se considrea acum fiecare muchie din graf ca avand capacitatea 1
 * 4. Se aplica algoritmul lui Ford-Fulkerson
 * 5. Se afiseaza numarul de muchii din multimea de muchii care au fost folosite
 */

// ---------------------- //
int n, m, e, s, d;
int total_nodes;
vector <vector<int>> graph;
vector <Edge> edges;
// ---------------------- //


// Construim o structura de date care ne va ajuta sa reprezentam un graf
struct Edge
{
    // Pozitia ne va trebui la Ford-Fulkerson
    int from, to, capacity, pozitie;
};

// Functia care adauga o muchie in graful rezidual
void addEdge (int x, int y)
{
    // In lista de adiacenta o sa pastram indexul muchiei
    int index = edges.size();

    // Creem muchia
    Edge e1 = {x, y, 1, index + 1};

    // Adaugam muchia in lista de adiacenta
    graph[y].push_back(index + 1);
    edges.push_back(e1);

    // Trebuie sa adaugam si muchia inversa pentru graful residual
    Edge e2 = {y, x, 0, index};
    graph[x].push_back(index);

}

// Folosim BFS pentru a determina daca exista un drum de la sursa la destinatie
// In Ford-Fulkerson vom folosi BFS pentru a determina daca exista un drum de la sursa la destinatie, care sa aiba capacitatea mai mare decat 0
// Asta inseamna ca mai putem adauga flux pe acel drum

// Vector de parinti pentru a putea parcurge arborele bfs
vector<int> tata;
// Vector unde tinem daca un nod a fost vizitat sau nu
vector<bool> vizitat;

int bfs ()
{
    tata.clear();
    tata.resize(total_nodes, -1);
    vizitat.clear();
    vizitat.resize(total_nodes, false);

    // Vom porni intotdeauna de la sursa
    vizitat[s] = true;
    // Coada in care vom retine nodurile
    queue<int> q;
    q.push(s);
    // Cat timp mai avem noduri in coada pargurgem graful
    while (!q.empty())
    {
        int nod = q.front();
        q.pop();
        // Parcurgem muchiile din lista de adiacenta, care sunt
        // retinute sub forma de index catre muchia din vectorul de muchii
        for (auto index_muchie: graph(nod))
        {
            // Deschidem muchia
            Edge e = edges[index_muchie];
            // Daca nodul nu a fost vizitat si muchia are capacitatea mai mare decat 0
            if (!vizitat[e.to] && e.capacity > 0)
            {
                // Marchez nodul ca vizitat
                vizitat[e.to] = true;
                // Marchez parintele nodului
                tata[e.to] = index_muchie;
                // Daca am ajuns la destinatie, atunci am gasit un drum
                if (e.to == d)
                    return 1;
                // Adaug nodul in coada
                q.push(e.to);
            }
        }
    }
    if (vizitat[d])
        return 1;
    // Daca nu am gasit drum, atunci returnam 0
    return 0;
}

// Functia care calculeaza fluxul maxim
// Ford-Fulkerson
int fordFulkerson ()
{
    // Flux maxim
    int flux = 0;
    // Cat timp mai exista un drum de la sursa la destinatie
    while (bfs())
    {
        for (auto index_muchie: graph[d])
        {
            if (vizitat[edges[index_muchie].to && edges[edges[index].pozitie].capacity > 0])
            {
                int capactiate = INT_MAX;
                Edge e = edges[index_muchie];
                tata[d] = e.pozitie;
                int nod = d;
                while (nod != s)
                {
                    capactiate = min(capactiate, edges[tata[nod]].capacity);
                    nod = edges[tata[nod]].from;
                }
                nod = d;
                // Actualizam fluxul, deci mai trebuie sa parcurgem drumul de la destinatie la sursa
                while (nod != s)
                {
                    edges[tata[nod]].capacity -= capactiate;
                    edges[edges[tata[nod]].pozitie].capacity += capactiate;
                    nod = edges[tata[nod]].from;
                }
                flux += capactiate;
            }
        }
    }
    return flux;
}

}

int main ()
{
    fin >> n >> m >> e;
    // Calculam numarul total de noduri
    total_nodes = n + m + 2;
    // Construim sursa si destinatia
    // Stim ca nodurile incep de la 0 si sunt consecutive
    s = 0;
    d = total_nodes - 1;
    // Construim graful
    graph.resize(total_nodes);


    // Citim muchiile
    for (int i = 0; i < e; i++)
    {
        int x, y;
        fin >> x >> y;
        // Adaugam muchia in lista de adiacenta
        addEdge(x, y + n);
    }

    // Adaugam muchiile de la sursa la nodurile din multimea A
    for (int i = 1; i <= n; i++)
        addEdge(s, i);

    // Adaugam muchiile de la nodurile din multimea B la destinatie
    for (int i = n + 1; i <= n + m; i++)
        addEdge(i, d);

    // Aplicam Ford-Fulkerson
    fout << fordFulkerson() << endl;

    for(int i = 0; i < edges.size(); i++)
    {
        if(edges[i].from < edges[i].to && edges[i].from != 0 && edges[i].to != d - 1 && edges[i].capacity == 0)
            fout << edges[i].from << " " << edges[i].to - n << endl;
    }
    return 0;
}