Cod sursa(job #2126519)

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

using namespace std;

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

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 ;
vector <int> graf[DMAX];
vector <int> ::iterator vecin;

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];
        graf[x].push_back(y);
        graf[y].push_back(x);
    }
    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];
        pusInCoada[actual] = false;
        primul++;
        for(vecin = graf[actual].begin(); vecin != graf[actual].end(); vecin++){
            //pun conditia de capacitate ca sa rec prin nodurile care imi ofera o inbunatatire a costului
            if(capacitate[actual][*vecin] > flux[actual][*vecin] && (costDrum[*vecin] == INFIN || costDrum[*vecin] > costDrum[actual] + cost[actual][*vecin])){
                costDrum[*vecin] = costDrum[actual] + cost[actual][*vecin];
                if(pusInCoada[*vecin] == false){
                    coada[++ultimul] = *vecin;
                    pusInCoada[*vecin] = true;
                }
            }
        }
    }
    costDrumTotal = costDrum[D];
}

inline 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){
        int tataElem = poz / 2;
        if(costDrum[heap[poz]] < costDrum[heap[tataElem]]) {
            interschimbare(poz, tataElem);
            verificareDeasupra(tataElem);
        }
    }
}

inline void validareInJos(int poz){
    int pozFiu = 0;
    int fiuStanga = poz * 2;
    if(fiuStanga <= lgHeap){
        pozFiu = fiuStanga;
        int fiuDreapta = fiuStanga + 1;
        if((fiuDreapta <= lgHeap) && costDrum[heap[fiuStanga]] > costDrum[heap[fiuDreapta]]){
            pozFiu = fiuDreapta;
        }
        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){
            for(vecin = graf[i].begin(); vecin != graf[i].end(); vecin++){
                if(costDrum[*vecin] != INFIN) {
                    cost[i][*vecin] += costDrum[i] - costDrum[*vecin];
                }
            }
        }
    }
}

inline bool 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);
        for(vecin = graf[nodMinim].begin();vecin != graf[nodMinim].end(); vecin++){
            if(flux[nodMinim][*vecin] < capacitate[nodMinim][*vecin]){
                if(costDrum[*vecin] > costDrum[nodMinim] + cost[nodMinim][*vecin]){
                    costDrum[*vecin] = costDrum[nodMinim] + cost[nodMinim][*vecin];
                    tata[*vecin] = nodMinim;
                    verificareDeasupra(pozNodInHeap[*vecin]);
                }
            }
        }
    }
    return costDrum[D]!= INFIN;
}

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;
}