Cod sursa(job #2962430)

Utilizator HAUBAUHAULICA TUDOR HAUBAU Data 8 ianuarie 2023 16:08:57
Problema Taramul Nicaieri Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.11 kb
#include <bits/stdc++.h>

using namespace std;

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

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

void read()
{
    fin >> n;
    /// S=0, multimea A = {1,2...,n}, multimea B = {n+1,...,n+n}, T=n+m+1
    N = 2*n + 1;
    for(int i = 1; i <= n; ++i)
    {
        fin >> x >> y;
        /// s la A
        g[0].emplace_back(i,x);
        g[i].emplace_back(0, 0);
        /// B la t
        g[i+n].emplace_back(N,y);
        g[N].emplace_back(i+n, 0);
    }
    /// A la B
    for(int i = 1; i <= n; ++i)
        for(int j = n + 1; j <= 2*n; ++j){
            if(j - i != n)
                g[i].emplace_back(j,1);
            g[j].emplace_back(i, 0);
        }
}

void gafis(){
    for(int i = 0; i <= N; ++i)
        for(auto nod : g[i])
            fout << i << " " << nod.first<< " " << nod.second << '\n';
}

void afis(){
    for(int i = 1; i <= n; ++i){
        for(auto nod : g[i]){
            if(!nod.second && nod.first > n)
                fout << i <<" " << nod.first - n << '\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] = true;

    /// 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 (auto p : g[nod])
            if (!viz[p.first] && p.second > 0)
            {
                q.push(p.first);
                parent[p.first] = nod;
                viz[p.first] = true;
            }
    }
    return false;
}
inline int flux()
{
    /// cat timp avem drumuri
    while (bfs())
    {
        for (int i = 0; i <= N; i++)
        {
            for(auto p : g[i]){
                if(p.first == N && p.second > 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++) {
                        int current_flow;
                        for(auto p : g[path[j]])
                            if(p.first == path[j + 1])
                                current_flow = p.second;

                        flow_minim = min(flow_minim, current_flow);
                    }

                    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++) {
                        for (int it = 0; it < g[path[j]].size(); ++it)
                            if(g[path[j]][it].first == path[j + 1])
                                g[path[j]][it].second -= flow_minim;

                        /// pt graful rezidual
                        for(int it = 0; it < g[path[j+1]].size(); ++it)
                            if(g[path[j+1]][it].first == path[j])
                                g[path[j+1]][it].second += flow_minim;
                    }
                }
            }
        }
    }

    return maxflow;
}

int main()
{
    read();
    fout << flux() << "\n";
    afis();

    return 0;
}