Cod sursa(job #2461188)

Utilizator iordache.bogdanIordache Ioan-Bogdan iordache.bogdan Data 24 septembrie 2019 23:57:40
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.52 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() && -pq.top().first != distance[pq.top().second])
            pq.pop();
        if (pq.empty())
            break;
        int currNode = pq.top().second;
        int currDist = -pq.top().first;
        fixed[currNode] = true;
        pq.pop();

        for (int edgeIndex : graph[currNode]) {
            // assert(edges[edgeIndex].normalised_cost >= 0 || edges[edgeIndex].flow == edges[edgeIndex].capacity);
            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;
                if (edges[edgeIndex].to == destination && realDistance->at(destination) == 51) {
                    // std::cerr << currNode << ' ' << realDistance->at(currNode) << ' ' << edges[edgeIndex].cost << std::endl;
                }
                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;
    // int cnt = 16;
    while (dijkstra(  nodeCount, source, destination, graph, *edges
                    , &minCostPath, &prev, &realDistance)) {
        int addFlow = kInf, cst = 0;
        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);
            cst += edges->at(idx).cost;
            // if (cnt) std::cerr << edges->at(idx).to + 1 << ' ';
        }

        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);
        // if (cnt) {std::cerr << std::endl << addFlow << ' ' << minCostPath << " " << cst << " " << realDistance[destination] << std::endl; cnt--;}

        // if (cnt && minCostPath != cst) {
            // std::cerr << "HERE\n";
            // for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from]) {
                // std::cerr << edges->at(idx).cost << ' ';
            // }
            // std::cerr << std::endl;
            // for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from])
                // std::cerr << realDistance[edges->at(idx).to] << ' ';
            // std::cerr << realDistance[source] << std::endl;
            // for (int idx = prev[destination]; idx >= 0; idx = prev[edges->at(idx).from])
                // std::cerr << edges->at(idx).to << ' ';
            // std::cerr << source << std::endl;
        // }
    }

    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!