Cod sursa(job #2987494)

Utilizator matei.tudoseMatei Tudose matei.tudose Data 2 martie 2023 13:29:03
Problema Flux maxim de cost minim Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.79 kb
#include <fstream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

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

const int NMAX = 350, INF = 0x3f3f3f3f;

vector<int> graf[NMAX + 5];
queue<int> coada;
int N, M, capacitate[NMAX + 5][NMAX + 5], flow[NMAX + 5][NMAX + 5], tata_de[NMAX + 5], cost[NMAX + 5][NMAX + 5], dist[NMAX + 5];
int startNod, endNod;


// Retinem in aceasta structura nodul vecin cu care se ajunge cu dist in endNod
// De asemenea, supraincarcam operatorul < pentru a-l face min heap
struct elemHeap
{
    int dist, nod;
    bool operator<(const elemHeap& otherElem)const
    {
        return dist > otherElem.dist;
    }
};

// Implementare Bellman-Ford optimizat cu coada a.k.a SPFA

bool bellmanFord()
{
    memset(tata_de, 0, sizeof tata_de);
    memset(dist, INF, sizeof dist);
    coada.push(startNod);
    dist[startNod] = 0;
    while (!coada.empty())
    {
        int nod_curent = coada.front();
        coada.pop();
        for (int i = 0; i < graf[nod_curent].size(); i++)
        {
            int vecin = graf[nod_curent][i];
            if (capacitate[nod_curent][vecin] - flow[nod_curent][vecin] > 0 && dist[vecin] > dist[nod_curent] + cost[nod_curent][vecin])
            {
                dist[vecin] = dist[nod_curent] + cost[nod_curent][vecin];
                tata_de[vecin] = nod_curent;
                coada.push(vecin);
            }
        }
    }
    return dist[endNod] != INF;
}

int main()
{
    fin >> N >> M >> startNod >> endNod;
    for (int i = 0; i < M; i++)
    {
        int from, to, capacity, cost_muchie;
        fin >> from >> to >> capacity >> cost_muchie;
        graf[from].push_back(to);
        graf[to].push_back(from);
        capacitate[from][to] = capacity;
        cost[from][to] = cost_muchie;
        // Ca sa ne intoarcem ca si cum nu am fi fost prin nod
        cost[to][from] = -cost_muchie;
    }
    int max_flow = 0;
    while (bellmanFord())
    {
        // Optimizare: luam vecinii cu distantele cele mai mici pana la endNod
        priority_queue<elemHeap> bestVecini;
        for (int i = 0; i  < graf[endNod].size(); i++)
        {
            int vecin = graf[endNod][i];
            int distanta = dist[vecin] + cost[vecin][endNod];
            bestVecini.push({distanta, vecin});
        }
        while (!bestVecini.empty())
        {
            int fluxMin, vecin = bestVecini.top().nod, dist_la_final = bestVecini.top().dist;
            // startNod nu are tata, dar este un vecin bun
            if (tata_de[vecin] == 0 && vecin != startNod)
                continue;
            if (capacitate[vecin][endNod] - flow[vecin][endNod] <= 0)
                continue;
            if (vecin == startNod)
            {
                fluxMin = capacitate[startNod][endNod] - flow[startNod][endNod];
                flow[startNod][endNod] += fluxMin;
                flow[endNod][startNod] -= fluxMin;
                max_flow += fluxMin * dist_la_final;
                bestVecini.pop();
                continue;
            }
            fluxMin = capacitate[vecin][endNod] - flow[vecin][endNod];
            while (vecin != startNod)
            {
                fluxMin = min(fluxMin, capacitate[tata_de[vecin]][vecin] - flow[tata_de[vecin]][vecin]);
                vecin = tata_de[vecin];
            }
            if (fluxMin == 0)
                continue;
            vecin = bestVecini.top().nod;
            flow[vecin][endNod] += fluxMin;
            flow[endNod][vecin] -= fluxMin;
            while (vecin != startNod)
            {
                flow[tata_de[vecin]][vecin] += fluxMin;
                flow[vecin][tata_de[vecin]] -= fluxMin;
                vecin = tata_de[vecin];
            }
            max_flow += fluxMin * dist_la_final;
            bestVecini.pop();
        }
    }
    fout << max_flow << "\n";
    return 0;
}