Cod sursa(job #3272254)

Utilizator robertanechita1Roberta Nechita robertanechita1 Data 29 ianuarie 2025 00:10:45
Problema Cuplaj maxim in graf bipartit Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.54 kb
#include <bits/stdc++.h>

using namespace std;

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

struct Muchii {
    int x, y;
};
Muchii muchii[10003];

int N, n, m, k, x, y, g[10001][10001], maxflow;
queue<int> q;
bool viz[10001];
int parent[10001];

void read()
{
    fin >> n >> m >> k;
    /// S=0, multimea A = {1,2...,n}, multimea B = {n+1,...,n+m}, T=n+m+1
    N = n + m + 1;
    for (int i = 0; i < k; ++i)
    {
        fin >> x >> y;
        g[x][y + n] = 1;
        muchii[i].x = x;
        muchii[i].y = y + n;
    }
    /// adaugam muchii de la sursa la fiecare nod din multimea A
    for (int i = 1; i <= n; ++i)
        g[0][i] = 1;
    /// adaugam muchii de la fiecare nod din multimea B la sink
    for (int i = n + 1; i <= n + m; ++i)
        g[i][n + m + 1] = 1;
}

void afis() {
    for (int i = 0; i <= N; ++i) {
        for (int j = 0; j <= N; ++j)
            cout << g[i][j] << " ";
        cout << "\n";
    }
}

int bfs()
{
    /// folosim bfs pentru a verifica daca mai este un drum de la s la t
    /// folosim vectorul parent pentru a putea reconstrui drumul

    /// reinitializam tot
    while (!q.empty())
        q.pop();

    for (int i = 0; i <= N; i++)
    {
        parent[i] = 0;
        viz[i] = false;
    }
    q.push(0);
    viz[0] = 1;

    /// bfs
    while (!q.empty())
    {
        auto nod = q.front();
        q.pop();
        /// n reprezinta destinatia deci returnam true deoarece am gasit drum
        if (nod == N) return true;

        for (int i = 0; i <= N; i++)
            if (!viz[i] && g[nod][i] > 0)
            {
                q.push(i);
                parent[i] = nod;
                viz[i] = true;
            }
    }
    return false;
}

inline int flux()
{
    /// cat timp avem drumuri
    while (bfs())
    {
        for (int i = 0; i <= N; i++)
        {
            if (g[i][N] > 0 && viz[i])
            {
                int leaf = i;
                /// construim drumul
                vector <int> path;
                path.push_back(N);
                path.push_back(leaf);

                int nod = parent[leaf];

                if (nod == 0)
                    path.push_back(nod);
                else
                {
                    while (nod != 0)
                    {
                        path.push_back(nod);
                        nod = parent[nod];
                    }
                    path.push_back(0);
                }

                reverse(path.begin(), path.end());

                /// dupa ce am gasit drumul, vedem care este flow-ul minim si adaugam la rezultatul final

                int flow_minim = INT_MAX;

                for (int j = 0; j < path.size() - 1; j++)
                    flow_minim = min(flow_minim, g[path[j]][path[j + 1]]);

                maxflow += flow_minim;

                /// pt reconstruirea flow-ului
                /// scadem flow_minim din muchiile inspre destinatie si adunam pe muchiile in directie opusa
                for (int j = 0; j < path.size() - 1; j++)
                {
                    g[path[j]][path[j + 1]] -= flow_minim;
                    g[path[j + 1]][path[j]] += flow_minim;
                }
            }
        }
    }

    return maxflow;
}

int main()
{
    read();
    fout << flux() << "\n";
    for (int i = 0; i < k; ++i) {
        x = muchii[i].x;
        y = muchii[i].y;
        if (g[x][y] == 0)
            fout << x << " " << y - n << '\n';
    }
    return 0;
}