Cod sursa(job #2961853)

Utilizator anne_marieMessner Anne anne_marie Data 7 ianuarie 2023 05:27:50
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.74 kb
#include <fstream>
#include <iostream>
#include <climits>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
ifstream fin("fmcm.in");
ofstream fout("fmcm.out");

struct edge{
    int node;
    int capacity;
    int flow;
    int cost;
    int new_cost;
};

vector<edge> ad[355];
int n, m, s, d; // nr noduri, nr muchii, sursa, destinatie
int x, y, c, z;
int new_costs[355], father[355];
queue<int> q;
priority_queue <pair<int, int>> pq; // pair(-costul minim pana la nod, nodul)
vector<int> path;

void bellmanFord() {
    for(int i = 1; i <= n; i ++)
        new_costs[i] = INT_MAX;

    new_costs[s] = 0;
    q.push(s);
    while(!q.empty()) {
        int node = q.front();
        q.pop();
        for(auto vec : ad[node]) {
            if(new_costs[vec.node] > new_costs[node] + vec.cost){
                new_costs[vec.node] = new_costs[node] + vec.cost;
                q.push(vec.node);
            }
        }
    }
}

int dijkstra() {
    // initializari
    for(int i = 1; i <= n; i ++) {
        new_costs[i] = INT_MAX;
        father[i] = 0;
    }
    new_costs[s] = 0;
    pq.push(make_pair(0, s));

    while(!pq.empty()) {
        int node = pq.top().second;
        pq.pop();

        for(auto vec : ad[node]) {
            if((new_costs[vec.node] > new_costs[node] + vec.new_cost) && (vec.flow < vec.capacity)) {
                new_costs[vec.node] = new_costs[node] + vec.new_cost;
                father[vec.node] = node;
                pq.push(make_pair(-new_costs[vec.node], vec.node));
            }
        }
    }
    if(new_costs[d] != INT_MAX)
        return 1;
    else
        return 0;
}

int findPosition(int node, int vec){

    for(int i = 0; i < ad[node].size(); i ++)
        if(ad[node][i].node == vec)
            return i;
    return -1;
};



int main() {
    fin >> n >> m >> s >> d;
    for(int i = 1; i <= m; i ++) {
        fin >> x >> y >> c >> z;
        ad[x].push_back({y, c,0, z, z});
    }


    // calculeaza costurile posibil negative de la sursa la destinatie folosind Bellman-Ford
    bellmanFord();


    // adaug la fiecare muchie un nou cost => new_cost = cost + new_costs[x] - new_costs[y]
    for(int i = 1; i <= n; i ++)
        for(int j = 0; j < ad[i].size(); j ++) {
            ad[i][j].new_cost = ad[i][j].cost + new_costs[i] - new_costs[ad[i][j].node];
        }



    // adaug muchiile inverse de de capacity = 0 si flow  = 0
    for(int i = 1; i <= n; i ++)
        for(int j = 0;  j < ad[i].size(); j ++)
            if(ad[i][j].capacity != 0) {
                ad[ad[i][j].node].push_back({i, 0, 0, -ad[i][j].cost, -ad[i][j].new_cost});
            }


    // flux cu Dijkstra
    while(dijkstra()) {
        int sth = d;
        path.clear();

        // pun drumul gasit in vectorul path
        while(father[sth] != 0) {
            path.push_back(father[sth]);
            sth = father[sth];
        }

        // calculez fluxul maxim pe acest drum
        int max_flow = INT_MAX;
        sth = d;
        while (father[sth] != 0) {
            int pos = findPosition(father[sth], sth);

            max_flow = min(max_flow, ad[father[sth]][pos].capacity - ad[father[sth]][pos].flow);
            sth = father[sth];
        }

        // adun fluxul pe fiecare muchie; scad fluxul pe muchiile inverse
        sth = d;
        while (father[sth] != 0) {
            int pos1 = findPosition(father[sth], sth);
            ad[father[sth]][pos1].flow += max_flow;

            int pos2 = findPosition(sth, father[sth]);
            ad[sth][pos2].flow -= max_flow;
            sth = father[sth];
        }
    }
    int result = 0;
    for(int i = 1; i <= n; i ++) {
        for(auto v : ad[i]) {
            if(v.flow > 0)
                result = result + v.flow * v.cost;
        }
    }
    fout << result << '\n';
    return 0;

}