Cod sursa(job #2460617)

Utilizator iordache.bogdanIordache Ioan-Bogdan iordache.bogdan Data 24 septembrie 2019 02:40:46
Problema Flux maxim de cost minim Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.14 kb
#include <bits/stdc++.h>

struct Edge {
    int from;
    int to;
    int capacity;
    int cost;
    int flow;
    int normalised_cost;
};

typedef std::vector<std::vector<int>> Graph_t;
const int kInf = 0x3f3f3f3f;

void bellmanFord(  const int &source, const int &nodeCount
                 , const Graph_t &graph
                 , const std::vector<Edge> &edges
                 , std::vector<int> *distance) {
    distance->assign(nodeCount, kInf);
    distance->at(source) = 0;

    std::vector<bool> inQueue(nodeCount, false);
    std::queue<int> queue;
    queue.push(source);
    inQueue[source] = true;

    while (!queue.empty()) {
        int currNode = queue.front();
        queue.pop();
        inQueue[currNode] = false;

        for (int edgeIndex : graph[currNode]) {
            if (distance->at(edges[edgeIndex].to) > distance->at(currNode)
                                                    + edges[edgeIndex].cost
                && edges[edgeIndex].capacity > edges[edgeIndex].flow) {

                distance->at(edges[edgeIndex].to) =   distance->at(currNode)
                                                   + edges[edgeIndex].cost;
                if (!inQueue[edges[edgeIndex].to]) {
                    queue.push(edges[edgeIndex].to);
                    inQueue[edges[edgeIndex].to] = true;

                }
            }
        }
    }

}

void normaliseEdges(  std::vector<Edge> *edges
                    , const std::vector<int> &distance) {
    for (Edge& edge : *edges) {
        edge.normalised_cost =
            edge.cost + distance[edge.from] - distance[edge.to];
    }
}

bool dijkstra(  const int &nodeCount, const int &source, const int &destination
              , const Graph_t &graph
              , const std::vector<Edge> &edges
              , int *minCost
              , std::vector<int> *prev
              , std::vector<int> *realDistance) {
    realDistance->assign(nodeCount, kInf);
    realDistance->at(source) = 0;
    std::vector<int> distance(nodeCount, kInf);
    distance[source] = 0;
    prev->assign(nodeCount, -1);
    std::priority_queue<std::pair<int, int>> pq;
    pq.emplace(0, source);
    std::vector<bool> fixed(nodeCount, false);

    while (true) {
        while (!pq.empty() && fixed[pq.top().second])
            pq.pop();
        if (pq.empty())
            break;
        int currNode = pq.top().second;
        int currDist = -pq.top().first;
        fixed[currNode] = true;

        for (int edgeIndex : graph[currNode]) {
            if (   edges[edgeIndex].flow < edges[edgeIndex].capacity
                && distance[edges[edgeIndex].to] >
                       currDist + edges[edgeIndex].normalised_cost
            ) {
                distance[edges[edgeIndex].to] =
                    currDist + edges[edgeIndex].normalised_cost;
                realDistance->at(edges[edgeIndex].to) =
                    realDistance->at(currNode) + edges[edgeIndex].cost;
                prev->at(edges[edgeIndex].to) = edgeIndex;
                pq.emplace(-distance[edges[edgeIndex].to], edges[edgeIndex].to);
            }
        }
    }

    *minCost = realDistance->at(destination);
    return prev->at(destination) != -1;
}

int64_t getMinCostForMaxFlow(  const int &nodeCount
                             , const int &source
                             , const int &destination
                             , const Graph_t &graph
                             , std::vector<Edge> *edges) {
    int64_t minCost = 0;
    std::vector<int> prev, realDistance;
    int minCostPath;
    while (dijkstra(  nodeCount, source, destination, graph, *edges
                    , &minCostPath, &prev, &realDistance)) {
        int addFlow = kInf;
        for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
            addFlow = std::min(  addFlow
                               , edges->at(idx).capacity - edges->at(idx).flow);
        }

        for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
            edges->at(idx).flow += addFlow;
            edges->at(idx ^ 1).flow -= addFlow;
        }

        minCost += 1LL * minCostPath * addFlow;
        // normaliseEdges(edges, realDistance);
    }

    return minCost;
}

int main() {
    std::ifstream cin("fmcm.in");
    std::ofstream cout("fmcm.out");

    int nodeCount, edgeCount;
    cin >> nodeCount >> edgeCount;
    int source, destination;
    cin >> source >> destination;
    source--; destination--; // index nodes from 0

    std::vector<Edge> edges(2 * edgeCount);
    Graph_t graph(nodeCount);
    for (int i = 0; i < edgeCount; ++i) {
        int from, to, capacity, cost;
        cin >> from >> to >> capacity >> cost;

        // index nodes from 0
        from--; to--;

        edges[2*i] = Edge {from, to, capacity, cost, 0, 0};
        graph[from].push_back(2*i);

        edges[2*i + 1] = Edge {to, from, 0, -cost, 0, 0};
        graph[to].push_back(2*i + 1);
    }

    std::vector<int> distance;
    bellmanFord(source, nodeCount, graph, edges, &distance);

    normaliseEdges(&edges, distance);

    cout << getMinCostForMaxFlow(nodeCount, source, destination, graph, &edges)
         << std::endl;

    return 0;
}

//Trust me, I'm the Doctor!