Cod sursa(job #3189583)

Utilizator Maria_VerdesVerdes Maria-Ioana Maria_Verdes Data 6 ianuarie 2024 10:52:21
Problema Cc Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.58 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <climits>

using namespace std;

ifstream f("cc.in");
ofstream g("cc.out");

int main()
{
    int n, suma = 0;
    f >> n;

    // vrem sa facem cuplajul de cost minim => cuplaj + Bellman Ford

    // nodurile calculator vor fi de la n + 1 la 2 * n
    // nodul 0 = nodul de start
    // nodul n * 2 + 1 = nodul de finish
    int last = 2 * n + 1;

    vector <vector <int>> vecini(last + 1, vector <int> ());  // lista de adiacenta - pt bfs
    vector <vector <int>> cost(last + 1, vector <int> (last + 1, 0));
    vector <vector <int>> capacitate(last + 1, vector <int> (last + 1, 0));
    vector <vector <int>> flux(last + 1, vector <int>(last + 1, 0));

    // citim costurile
    for(int elev = 1; elev <= n; elev++)
        for(int calc = n + 1; calc <= 2 * n; calc++)
        {
            int cst;
            f >> cst;
            cost[elev][calc] = cst;
            cost[calc][elev] = -cst; // o sa pierd daca aveam selectata muchia si decid sa ma intorc
            vecini[elev].push_back(calc);
            vecini[calc].push_back(elev);
            capacitate[elev][calc] = 1;
        }

    f.close();

    // initializare nod de start
    for(int elev = 1; elev <= n; elev++)
    {
        vecini[elev].push_back(0);
        vecini[0].push_back(elev);
        capacitate[0][elev] = 1;
    }

    // initializare nod final
    for(int calc = n + 1; calc <= 2 * n; calc++)
    {
        vecini[calc].push_back(last);
        vecini[last].push_back(calc);
        capacitate[calc][last] = 1;
    }

    // alogritmul pentru determinarea fluxului maxim -> vrem sa-l facem cu bellman ford
    bool avemDrumDeCrestere = true;
    while(avemDrumDeCrestere)
    {
        avemDrumDeCrestere = false;

        //cautam cu bellman ford un lant de cost minim in care sa putem creste fluxul
        queue <int> q;
        vector <int> tata(last + 1); // tinem tatal fiecarui nod din lant, daca muchia intoarce flux => -tata
        //vector <bool> vis(last + 1, false); // vector de vizitati
        vector <int> cost_temp(last + 1, INT_MAX); // costuri pt bellman-ford

        //initializare vector de tati
        for(int i = 0; i <= last; i++)
            tata[i] = i;

        q.push(0);
        //vis[0] = true;
        cost_temp[0] = 0;
        while(!q.empty())
        {
            int nod = q.front();
            q.pop();
            for(int i = 0; i < vecini[nod].size(); i++)
            {
                int vecin = vecini[nod][i];

                //daca pot imbunatati si fluxul si costul
                if(capacitate[nod][vecin] > flux[nod][vecin] && cost_temp[vecin] > cost_temp[nod] + cost[nod][vecin])
                {
                    q.push(vecin);
                    //vis[vecin] = true;
                    tata[vecin] = nod;
                    cost_temp[vecin] = cost_temp[nod] + cost[nod][vecin];

                    // daca am gasit un lant pana la nodul final
                    if(vecin == last)
                    {
                        avemDrumDeCrestere = true;
                        break;
                    }
                }
            }
        }

        // daca avem drum
        if(avemDrumDeCrestere)
        {
            // il parcurgem si aflam fluxul maxim pe care putem sa-l pusham pe toate muchiile
            int nodCurent = last;
            int fluxMaxim = 100; // fluxul nostru maxim pe un drum oricum e 1 =)
            while(nodCurent != 0)
            {
                int predecesor = tata[nodCurent];
                if(fluxMaxim > capacitate[predecesor][nodCurent] - flux[predecesor][nodCurent])
                    fluxMaxim = capacitate[predecesor][nodCurent] - flux[predecesor][nodCurent];

                nodCurent = predecesor;
            }

            // il parcurgem si pusham fluxul respectiv pe fiecare muchie
            nodCurent = last;
            while(nodCurent != 0)
            {
                int predecesor = tata[nodCurent];

                flux[predecesor][nodCurent] += fluxMaxim;
                flux[nodCurent][predecesor] -= fluxMaxim;

                nodCurent = predecesor;
            }
        }
    }

    // vedem ce muchii am folosit pentru a realiza cuplajul + costul lor
    for(int elev = 1; elev <= n; elev++)
        for(int calc = n + 1; calc <= 2 * n; calc++)
            if(flux[elev][calc])
            {
                suma += cost[elev][calc];
                continue;
            }

    g << suma;

    g.close();
    return 0;
}