Cod sursa(job #2833898)

Utilizator Vlad_AnicaAnica-Popa Vlad-Ioan Vlad_Anica Data 15 ianuarie 2022 22:09:22
Problema Flux maxim de cost minim Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.7 kb
#include <iostream>
#include <stdio.h>
#include <utility>
#include <vector>

using namespace std;
const int INF = 1e8;

struct pack {
    int nd, cst;
};
struct flm {
    int cap, cst;
};

class Heap {

private:
    int heapSize;

public:
    int maxHeapSize;
    pack *arr;
    int *pos;

    Heap(int maxHeapSize) {
        this -> maxHeapSize = maxHeapSize;
        this -> heapSize = 0;
        this -> arr = new pack[maxHeapSize + 1];
        this -> pos = new int[maxHeapSize + 1];
    }

    inline int lSon(int node) {
        return node << 1;
    }
    inline int rSon(int node) {
        return (node << 1) + 1;
    }
    inline int father(int node) {
        return node >> 1;
    }
    inline void sift(int node) {
        int son;
        do {
            son = 0;
            if (lSon(node) <= heapSize && arr[lSon(node)].cst < arr[node].cst)
                son = lSon(node);
            if (rSon(node) <= heapSize && arr[rSon(node)].cst < arr[son].cst)
                son = rSon(node);

            if (son) {
                pos[arr[node].nd] = son;
                pos[arr[son].nd] = node;
                swap(arr[node], arr[son]);
                node = son;
            }

        }while (son);
    }
    inline void percolate(int node) {
        while (father(node) && arr[father(node)].cst > arr[node].cst) {
            pos[arr[father(node)].nd] = node;
            pos[arr[node].nd] = father(node);
            swap(arr[father(node)], arr[node]);
            node = father(node);
        }
    }
    inline void pop() {
        pos[arr[heapSize].nd] = 1;
        swap(arr[1], arr[heapSize--]);
        sift(1);
    }
    inline void inserthp(pack newE) {
        arr[++heapSize] = newE;
        pos[newE.nd] = heapSize;
        percolate(heapSize);
    }
    inline int getSize() {
        return heapSize;
    }
    inline pack top() {
        return arr[1];
    }
    inline int getPos(int nd) {
        return pos[nd];
    }
    inline bool isempty() {
        if (heapSize)
            return 0;
        return 1;
    }
    void change (int pos, int val) {
        arr[pos].cst = val;
        percolate(pos);
    }

};

class minCostFlow {

public:
    int n;
    vector<int> *edges;
    int *father;
    int **flow;
    flm **ntwrk;
    bool *vis;
    int src, dest;
    int minCost;

    minCostFlow(int n, vector<pair<int, flm>> *edges, int src, int dest) {
        this -> n = n;
        this -> edges = new vector<int>[n + 1];
        this -> father = new int[n + 1];
        this -> flow = new int*[n + 1];
        this -> ntwrk = new flm*[n + 1];
        this -> vis = new bool[n + 1];
        this -> src = src;
        this -> dest = dest;

        for (int i = 1; i <= n; i++) {
            this -> flow[i] = new int[n + 1];
            this -> ntwrk[i] = new flm[n + 1];
            for (int j = 0; j <= n; j++) {
                this -> flow[i][j] = 0;
                this -> ntwrk[i][j] = {0, 0};
            }
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++)
                this -> flow[i][j] = 0;

            int len = edges[i].size();
            for (int j = 0; j < len; j++) {
                pair<int, flm> pr = edges[i][j];
                this -> edges[i].push_back(pr.first);
                this -> ntwrk[i][pr.first] = pr.second;
                this -> ntwrk[pr.first][i] = {-pr.second.cap, -pr.second.cst};

            }
        }
    }


    inline void preprocess() {
        minCost = INF;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                minCost = min(minCost, ntwrk[i][j].cst);

        if (minCost < 0)
            minCost = -minCost;

        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                ntwrk[i][j].cst += minCost;
    }
    inline bool dijkstra() {
        for (int i = 0; i <= n; i++)
            vis[i] = 0;

        Heap myHeap(n);
        myHeap.inserthp({src, 0});
        father[src] = 0;
        int minPth = INF;
        vis[src] = 1;
        while (!myHeap.isempty()) {
            pack curr = myHeap.top();
            int len = edges[curr.nd].size();
            for (int i = 0; i < len; i++) {
                pack nxt = {edges[curr.nd][i], ntwrk[curr.nd][edges[curr.nd][i]].cst};

                if (nxt.nd == dest && flow[curr.nd][nxt.nd] != ntwrk[curr.nd][nxt.nd].cap && minPth > curr.cst + nxt.cst) {
                    vis[dest] = 1;
                    father[dest] = curr.nd;
                    minPth = curr.cst + nxt.cst;
                    continue;
                }

                if (flow[curr.nd][nxt.nd] != ntwrk[curr.nd][nxt.nd].cap) {
                    if (!vis[nxt.nd]) {
                        myHeap.inserthp({nxt.nd, curr.cst + nxt.cst});
                        father[nxt.nd] = curr.nd;
                        vis[nxt.nd] = 1;
                    }
                    else {
                        int pos = myHeap.getPos(nxt.nd);
                        if (myHeap.arr[pos].cst > curr.cst + nxt.cst) {
                            father[nxt.nd] = curr.nd;
                            myHeap.change(pos, curr.cst + nxt.cst);
                        }
                    }
                }
            }
            myHeap.pop();
        }
        return vis[dest];
    }
    inline int pushFlow() {
        int son = dest;
        int minFlow = INF, cstPth;
        while (father[son]) {
            minFlow = min(ntwrk[father[son]][son].cap - flow[father[son]][son], minFlow);
            son = father[son];
        }
        cstPth = 0;
        son = dest;

        while (father[son]) {
            flow[father[son]][son] += minFlow;
            cstPth += minFlow * ntwrk[father[son]][son].cst - minFlow * minCost;
            son = father[son];
        }
        return cstPth;
    }
    inline int solveNetwork() {
        int cstFin = 0;
        while (dijkstra())
            cstFin += pushFlow();
        return cstFin;
    }

};

int main()
{
    vector<pair<int, flm>> *edges;
    int n, m, src, dest, v1, v2, cst, cap;
    FILE *fin = fopen("fmcm.in", "r");
    fscanf(fin, "%d%d%d%d", &n, &m, &src, &dest);

    edges = new vector<pair<int, flm>>[n + 1];
    for (int i = 0; i < m; i++) {
        fscanf(fin, "%d%d%d%d", &v1, &v2, &cap, &cst);
        edges[v1].push_back({v2, {cap, cst}});
        edges[v2].push_back({v1, {-cap, -cst}});
    }
    fclose(fin);

    FILE *fout = fopen("fmcm.out", "w");
    minCostFlow slv(n, edges, src, dest);
    slv.preprocess();
    fprintf(fout, "%d", slv.solveNetwork());
    fclose(fout);

    return 0;
}