Cod sursa(job #2955114)

Utilizator IRadu1529Radu Ionescu IRadu1529 Data 16 decembrie 2022 11:49:00
Problema Cuplaj maxim in graf bipartit Scor 32
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.29 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <fstream>
#include <set>
using namespace std;


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

#define N 10001

int n, m, e, maxFlow;
int s, t;
int capacity[N][N];
vector<vector<int>> l(N, vector<int>());
vector<int> parent(N);
set<pair<int, int>> edges;
//O(N * M2)
int bfs(int s, int t) {
    parent[s] = -2; // orice != -1 si [0,n+m+1]
    queue<pair<int, int>> q;
    q.push({ s, 1e9 });

    while (!q.empty()) {
        int cur = q.front().first;
        int maxFlow = q.front().second;
        q.pop();

        for (int next : l[cur]) {
            if (parent[next] == -1 && capacity[cur][next]) {
                parent[next] = cur;
                int bottleneck = min(maxFlow, capacity[cur][next]);
                if (next == t)
                    return bottleneck;
                q.push({ next, bottleneck });
            }
        }
    }

    return 0;
}

void read() {
    fin >> n >> m >> e;

    while (e--) {
        int a, b;
        fin >> a >> b; // muchia a -> n+b
        l[a].push_back(n + b);
        l[n + b].push_back(a);
        capacity[a][n + b] = 1; // muchia de inaintare 
    }
}

int main() {

    read();

    s = 0; t = n + m + 1;

    for (int i = 1; i <= n; i++) { // concectam sursa la nodurile din A
        l[s].push_back(i);
        l[i].push_back(s);
        capacity[s][i] = 1;
    }

    for (int i = n + 1; i <= n + m; i++) { // concectam nodurile din B la destinatie
        l[i].push_back(t);
        l[t].push_back(i);
        capacity[i][t] = 1;
    }

    for (int i = 0; i <= n + m + 1; i++) // resetam parintii
        parent[i] = -1;

    int bottleneck;

    set<pair<int, int>> edges;

    while (bottleneck = bfs(s, t)) { // cat mai sunt path uri care mai accepta flux
        maxFlow += bottleneck;
        int node = t;
        
        int edgeCounter = 0;
        bool needToAdd = 1; // devine 0 doar daca am muchie de intoarcere, caz in care nu ma intereseaza traseul
        set<pair<int, int>> aux;

        while (node != s) { // mergem inapoi pe path ul gasit 
            
            int prev = parent[node];
            //cout << prev << " " << cur << "\n";                
           
            capacity[prev][node] -= bottleneck; // muchia de inaintare pierde din spatiu exact bottleneck
            capacity[node][prev] += bottleneck; // muchia de retur poate face undo cu exact bottleneck mai mult

            if (node > s && node < t && prev > s && prev < t) // doar muchii de inaintare dintre A si B
                aux.insert({ prev, node - n });

            if (prev > node) // am gasit o mucie de intoarcere deci nu ma intereseaza traseul
                needToAdd = 0;

            edgeCounter++;

            node = prev;

        }
        //cout << "\n\n";

        for (int i = 0; i <= n + m + 1; i++) // resetam parintii
            parent[i] = -1;
    
        if (needToAdd == 0) // daca am gasit o muchie de intoarcere nu adaugam muchiile traseului
            continue;

        for (auto i : aux)
            edges.insert(i);
    }

    fout << maxFlow << "\n";

    for (auto i : edges)
        fout << i.first << " " << i.second << "\n";

    return 0;
}