Cod sursa(job #2967291)

Utilizator maria-marianita.cucos@s.unibuc.roCucos Marianita [email protected] Data 19 ianuarie 2023 11:43:04
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.76 kb

// Flux maxim de cost minim
// Complexitate O(N*M^2*logN)

#include <bits/stdc++.h>
using namespace std;
ifstream f("fmcm.in");
ofstream g("fmcm.out");

int n, s, d, capacitate[351][351], cost[351][351], inQ[351], distVeche[351], dist[351], distNoua[351], parinte[351], raspuns;
vector<int> muchii[351];
queue<int>q;
priority_queue<pair<int, int> > pq; //desc

bool dijkstra() {
    // Initial niciun nod nu e vizitat
    for(int i = 0; i <= n; ++i)
        dist[i] = 1000000000;
    // Nodul sursa e vizitat si se afla la distanta 0
    dist[s] = 0;
    distNoua[s] = 0;
    pq.push({0, s});
    // Cat timp mai am elemente
    while(!pq.empty()) {
        int c = -pq.top().first;
        int nod = pq.top().second;
        pq.pop();
        // Daca am trecut deja prin nod continuam
        if(dist[nod] != c) {
            continue;
        }
        // Verific pentru toti vecinii daca pot forma un drum mai bun din nodul curent
        for(auto it : muchii[nod])
            // Daca am capacitate pe muchie
            if(capacitate[nod][it]) {
                int d = c + cost[nod][it];
                // Adaugam distVeche[nod] - distVeche[it] pentru a face costul pozitiv
                d += distVeche[nod] - distVeche[it];
                if(d < dist[it])
                {
                    // In dist pastrez costul modificat care e numai pozitiv
                    dist[it] = d;
                    // In distNoua pastrez costul adevarat al drumului care poate fi si negativ
                    distNoua[it] = distNoua[nod] + cost[nod][it];
                    // Momentan cel mai bun drum pana la vecin este prin nod
                    parinte[it] = nod;
                    // Adaug in coada vecinul si costul drumului pana la el
                    pq.push({-dist[it], it});
                }
            }
    }
    // Distanta veche pentru pasul urmator e acum distanta noua
    for(int i = 1; i <= n; ++i) {
        distVeche[i] = distNoua[i];
    }
    // Daca nu am ajuns la destinatie ma opresc
    if(dist[d] == 1000000000)
        return false;
    // Calculez fluxul pe care pot sa-l adaug pe drumul minim si costul
    int flux = 1000000000, rasp = 0;
    int nod = d;
    while(nod != s) {
        int p = parinte[nod];
        flux = min(flux, capacitate[p][nod]);
        rasp += cost[p][nod];
        nod = p;
    }
    // Adaug la raspuns costul fluxului adaugat
    raspuns += rasp * flux;
    // Adaug fluxul pe drumul gasit
    nod = d;
    while(nod != s) {
        int p = parinte[nod];
        capacitate[p][nod] -= flux;
        capacitate[nod][p] += flux;
        nod = p;
    }
    // Am gasit un drum pe care pot adauga flux
    return true;
}


// Calculez distanta minima de la sursa la toate nodurile
void bellmandFord() {
    for(int i = 0; i <= n; ++i)
        distVeche[i] = 1000000000;
    q.push(s);
    inQ[s] = 1;
    distVeche[s] = 0;
    while(!q.empty()) {
        int nod = q.front();
        inQ[nod] = 0;
        q.pop();
        for(auto vecin : muchii[nod])
            if(capacitate[nod][vecin] && distVeche[nod] + cost[nod][vecin] < distVeche[vecin]) {
                distVeche[vecin] = distVeche[nod] + cost[nod][vecin];
                if(!inQ[vecin]) {
                    q.push(vecin);
                    inQ[vecin] = 1;
                }
            }
    }
}


int main()
{
    int m;
    f >> n >> m >> s >> d;
    while(m--) {
        int x, y, c, z;
        f >> x >> y >> c >> z;
        muchii[x].push_back(y);
        muchii[y].push_back(x);
        capacitate[x][y] = c;
        cost[x][y] = z;
        cost[y][x] = -z;
    }

    bellmandFord();
    while(dijkstra());

    g << raspuns;

    g.close();
    f.close();
    return 0;
}