Cod sursa(job #3217101)

Utilizator adiadi11Adrian Ariton adiadi11 Data 21 martie 2024 00:32:31
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.36 kb
#include <iostream>
#include <fstream>

#include <vector>
#include <queue>
#define REVERSE 1
#define NORMAL 0
std::ifstream fin("fmcm.in");
std::ofstream fout("fmcm.out");
class Edge;
class Graph;


class Edge {
public:
    long long source;
    long long dest;
    long long cap;
    long long flow;
    long long type;
    long long cost;
    Edge *reverse;
    Edge(){
        type = 0;
        source = 0;
        dest = 0;
        cap = 0;
        flow = 0;
        cost = 0;
    }
    Edge(long long t=0) : type(t) {
        source = 0;
        dest = 0;
        cap = 0;
        flow = 0;
        cost = 0;
    }
    void point(Edge *rev) {
        this->reverse = rev;
    }
    Edge(long long s, long long d, long long c, long long co, long long t = 0) : source(s), dest(d), cap(c), flow(0), type(t), cost(co) {}

};

class Graph {
public:
    long long nodes;
    std::vector< std::vector<Edge *> > graph;
    std::vector<Edge *> all_edges;
    std::vector<Edge *> all_revedges;

    Graph(int n) : nodes(n) {
        graph.reserve(n+1);
    }

    void addEdge(long long s, long long d, long long c, long long co) {
        Edge *e1 = new Edge(s, d, c, co);
        Edge *e2 = new Edge(d, s, 0, -co, REVERSE);
        e1->point(e2);
        e2->point(e1);
        graph[s].push_back(e1);
        graph[d].push_back(e2);
        all_edges.push_back(e1);
        all_revedges.push_back(e2);
    }
};

namespace BellmanFord {
    std::vector<int> bellmanford(const Graph& g, int source) {
        std::vector <int> dist(g.nodes + 1, 1e9);
        std::vector <int> pred(g.nodes + 1, -1);
        dist[source] = 0;
        for (int i = 0; i < g.nodes - 1; ++i) {
            for (auto& edge : g.all_edges) {
                if (dist[edge->source] != 1e9 && dist[edge->source] + edge->cost < dist[edge->dest]) {
                    dist[edge->dest] = dist[edge->source] + edge->cost;
                    pred[edge->dest] = edge->source;
                }
            }
            
        }
        for (auto& edge : g.all_edges) {
            if (dist[edge->source] != 1e9 && dist[edge->source] + edge->cost < dist[edge->dest]) {
                std::cout << "Negative cycle\n";
            }

            int arcdist = edge->cost + dist[edge->source] - dist[edge->dest];
            if (arcdist < 0) 
                std::cout << "Bad bellman\n";
        }
        return dist;
    }
}

namespace Dijkstra {
    class EdgeEntryComparator {
    public:
        std::vector<int>& cost;
        EdgeEntryComparator(std::vector<int>& _cost) : cost(_cost) {}
        bool operator()(int a,  int b) {
            return this->cost[a] > this->cost[b];
        }
    };

    std::pair< std::vector<int>, Edge** > dijkstra_bef(const Graph& g, int source, std::vector<int>& distances_bf) {
        // std::vector<int> dist(g.nodes + 1, 1e9);
        std::vector<int> real_dist(g.nodes +1, 1e9);
        std::vector<int> dist(g.nodes + 1, 1e9);
        Edge *bef[1004];
        for (int  i = 0; i < g.nodes + 1; ++i)
            bef[i] = nullptr;

        auto lamb_comp = [&dist] (int a, int b) -> bool {
            return dist[a] > dist[b];
        };

        // T comp = T(dist);
        std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater< std::pair<int, int> > > pq;
        bool viz[1005] = {false};
        
        dist[source] = 0;
        real_dist[source] = 0;
        pq.push({0, source});
        viz[source] = false;
        while(!pq.empty()) {
            int node = pq.top().second;
            pq.pop();
            if (viz[node] == true) continue;
            viz[node] = true;
            for (Edge * edge : g.graph[node]) {
                int neigh = edge->dest;
                int new_d = dist[node] + edge->cost + distances_bf[node] - distances_bf[neigh];
                if (dist[neigh] > new_d
                    && edge->flow < edge->cap) { // added bc of flow
                    dist[neigh] = new_d;
                    real_dist[neigh] = real_dist[node] + edge->cost;
                    pq.push({dist[neigh], neigh});
                    bef[neigh] = edge;
                }
            }
        }
        for(int i=1; i<=g.nodes; i++) distances_bf[i]+=dist[i];
        return std::make_pair(real_dist, bef);
    }
}

long long max_flow_min_cost(Graph& g, long long source, long long dest) {
    int total_flow = 0;
    int flow_cost = 0;
    auto distances_bf = BellmanFord::bellmanford(g, source);

    while (1) {
        auto dist_pred = Dijkstra::dijkstra_bef(g, source, distances_bf);
        Edge** predec = dist_pred.second;
        auto dists = dist_pred.first;
        if (predec[dest] == nullptr)
            break;

        long long flow = 1e9;
        for (Edge *edge = predec[dest]; edge != nullptr; edge = predec[edge->source]) {
            flow = std::min(flow, edge->cap - edge->flow);
        }

        if (flow == 0)
            break;
        total_flow += flow;
        flow_cost += flow * dists[dest];
        for (Edge *edge = predec[dest]; edge != nullptr; edge = predec[edge->source]) {
            edge->flow = edge->flow + flow;
            edge->reverse->flow = edge->reverse->flow - flow;
        }

    }

    return flow_cost;
}

int main() {
    int n, m, so = 1, de;
    fin >> n >> m >> so >> de;
    Graph g(n);
    int s, d, c, co;
    for (int i = 0; i < m; ++i) {
        fin >> s >> d >> c >> co;
        g.addEdge(s, d, c, co);
    }

    fout << max_flow_min_cost(g, so, de);
}