Cod sursa(job #2126402)

Utilizator ruxandramateiMatei Ruxandra ruxandramatei Data 9 februarie 2018 16:38:59
Problema Flux maxim de cost minim Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 5.7 kb
#include <iostream>
#include <fstream>
#include <cstring>
#define DMAX 360
#define INFIN 1<<30

using namespace std;

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

struct nod{
    int val;
    nod * urm;
}*v[DMAX];

int n, m;//date de intrare
int S, D;
int capacitate[DMAX][DMAX], cost[DMAX][DMAX];
int flux[DMAX][DMAX];
int costDrum[DMAX],tata[DMAX];
int heap[DMAX],pozNodInHeap[DMAX], lgHeap;
int costMaxim,  costDrumTotal ;

void citire(){
    in >> n >> m >> S >> D;
    for(int i = 1; i <= m; i++){
        int x, y;
        in >> x >> y;
        in >> capacitate[x][y];
        in >> cost[x][y];
        cost[y][x] = -cost[x][y];

        nod * deAdaugat1 = new nod;
        deAdaugat1 -> val = y;
        deAdaugat1 -> urm = v[x];
        v[x] = deAdaugat1;

        nod * deAdaugat2 = new nod;
        deAdaugat2 -> val = x;
        deAdaugat2 -> urm = v[y];
        v[y] = deAdaugat2;
    }
    in.close();
}

void bellmann(){
    for(int i = 1; i<= n; i++){
        costDrum[i] = INFIN;
    }
    costDrum[S] = 0;//punctul de plecare

    int coada[DMAX], primul, ultimul;
    primul = ultimul = 1;
    coada[1] = S;

    bool pusInCoada[DMAX];
    memset(pusInCoada, false, sizeof(pusInCoada));
    pusInCoada[S] = true;

    while (primul <= ultimul){
        int actual = coada[primul];
        nod * parcurg = v[actual];
        pusInCoada[actual] = false;
        primul++;
        while(parcurg != NULL){
            //pun conditia de capacitate ca sa rec prin nodurile care imi ofera o inbunatatire a costului
            if(capacitate[actual][parcurg -> val] > flux[actual][parcurg -> val] && (costDrum[parcurg -> val] > costDrum[actual] + cost[actual][parcurg -> val])){
                costDrum[parcurg -> val] = costDrum[actual] + cost[actual][parcurg -> val];
                if(pusInCoada[parcurg -> val] == false){
                    coada[++ultimul] = parcurg -> val;
                    pusInCoada[parcurg -> val] = true;
                }
            }
            parcurg = parcurg -> urm;
        }
    }
    costDrumTotal = costDrum[D];
}

inline int tataElem(int poz){
    return poz/2;
}

inline int fiuStanga(int poz){
    return  poz * 2;
}

inline int fiuDreapta(int poz){
    return  poz * 2 + 1;
}

void interschimbare(int a, int b){
    swap(heap[a],heap[b]);
    swap(pozNodInHeap[heap[a]], pozNodInHeap[heap[b]]);
}

inline void verificareDeasupra(int poz){
    if(poz > 1){
        if(costDrum[heap[poz]] < costDrum[heap[tataElem(poz)]]) {
            interschimbare(poz, tataElem(poz));
            verificareDeasupra(tataElem(poz));
        }
    }
}

inline void validareInJos(int poz){
    int pozFiu = 0;
    if(fiuStanga(poz) <= lgHeap){
        pozFiu = fiuStanga(poz);
        if((pozFiu + 1 <= lgHeap) && costDrum[heap[pozFiu]] > costDrum[heap[fiuDreapta(poz)]]){
            pozFiu = fiuDreapta(poz);
        }
        if(costDrum[pozFiu] >= costDrum[heap[poz]]){
            pozFiu = 0;
        }
    }
    if(pozFiu != 0){
        interschimbare(poz, pozFiu);
        validareInJos(pozFiu);
    }
}

void stergereDinHeap(int poz){
    interschimbare(1,lgHeap);
    lgHeap--;
    validareInJos(poz);
}

void actualizareArcePozitiv(){
    for(int i = 1; i <= n; i++){
        if(costDrum[i] != INFIN){
            nod * parcurg = v[i];
            while(parcurg != NULL){
                if(costDrum[parcurg -> val] != INFIN) {
                    cost[i][parcurg->val] += costDrum[i] - costDrum[parcurg->val];
                }
                parcurg = parcurg -> urm;
            }
        }
    }
}

inline int Dijkstra(){
    actualizareArcePozitiv();
    for(int i = 1; i<= n; i++){
        costDrum[i] = INFIN;
    }
    costDrum[S] = 0;
    memset(tata, 0 , sizeof(tata));
    tata[S] = -1;
    //construiesc heapul, momentan nearanjat
    for(int i = 1; i<= n; i++){
        heap[i] = i;
        pozNodInHeap[i] = i;
    }
    interschimbare(1,S);//sursa va fi primul nod, oricum el este cel mai aproape de sursa
    lgHeap = n;//in heap am n elemente;
    while(lgHeap != 0 && (costDrum[heap[1]] != INFIN)){//cat timp avem un drum scurt
        int nodMinim = heap[1];
        stergereDinHeap(1);
        nod * parcurg = v[nodMinim];
        while (parcurg != NULL){
            if(flux[nodMinim][parcurg -> val] < capacitate[nodMinim][parcurg -> val]){
                if(costDrum[parcurg -> val] > costDrum[nodMinim] + cost[nodMinim][parcurg -> val]){
                    costDrum[parcurg -> val] = costDrum[nodMinim] + cost[nodMinim][parcurg -> val];
                    tata[parcurg -> val] = nodMinim;
                    verificareDeasupra(pozNodInHeap[parcurg -> val]);
                }
            }
            parcurg = parcurg -> urm;
        }
    }
    return (costDrum[D]!= INFIN) ? 1 : 0;
}

void fluxMaxim(){
    costMaxim = 0;
    for (bool existaDrumAmel = Dijkstra(); existaDrumAmel != 0; existaDrumAmel = Dijkstra()){
        int FluxMaximDePus = INFIN;
        //aflu capacitatea maxima pe care o pot pompa pe arcele din drum
        for(int intoarcere = D; intoarcere != S; intoarcere = tata[intoarcere]){
            int temp1 = capacitate[tata[intoarcere]][intoarcere];
            int temp2 = flux[tata[intoarcere]][intoarcere];
            FluxMaximDePus = min(temp1 - temp2, FluxMaximDePus);
        }
        //saturez drumul de ameliorare
        for(int intoarcere = D; intoarcere != S; intoarcere = tata[intoarcere]){
            flux[tata[intoarcere]][intoarcere] += FluxMaximDePus;
            flux[intoarcere][tata[intoarcere]] -= FluxMaximDePus;
        }
        costDrumTotal += costDrum[D];
        costMaxim += costDrumTotal * FluxMaximDePus;
    }
}

int main() {
    citire();
    bellmann();
    //folosesc algoritmul lui bellmann pentru a calcula initial distantele minime
    fluxMaxim();
    out << costMaxim;

    return 0;
}