Cod sursa(job #2850917)

Utilizator Vlad_AnicaAnica-Popa Vlad-Ioan Vlad_Anica Data 17 februarie 2022 19:30:25
Problema Flux maxim de cost minim Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 7.87 kb
#include <iostream>
#include <stdio.h>
#include <utility>
#include <vector>
#include <deque>


using namespace std;
const int INF = 1e8;

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


int cnt[1000][1000];


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);
        }
    }
    void pop() {
        pos[arr[heapSize].nd] = 1;
        swap(arr[1], arr[heapSize--]);
        sift(1);
    }
    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;
    int maxflow;
    int *minDist;

    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 -> minDist = new int[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;
            }
        }
    }

    void bellmanFord() {
        deque<int> q;
        bool *inQ = new bool[n + 1];
        for (int i = 1; i <= n; i++) {
            minDist[i] = INF;
            inQ[i] = 0;
        }
        minDist[src] = 0;
        inQ[src] = 1;
        q.push_back(src);
        int c = 0;
        while (!q.empty()) {
            c++;
            int curr = q.front();
            q.pop_front();
            inQ[curr] = 0;
            int len = edges[curr].size();
            for (int i = 0; i < len; i++) {
                int nxt = edges[curr][i];
                if (ntwrk[curr][nxt].cap) {
                    if (minDist[curr] + ntwrk[curr][nxt].cst < minDist[nxt]) {
                        cnt[curr][nxt]++;
                        minDist[nxt] = minDist[curr] + ntwrk[curr][nxt].cst;
                        if (!inQ[nxt]) {
                            inQ[nxt] = 1;
                            q.push_back(nxt);
                        }
                    }
                }
            }
        }
    }

    inline void preprocess() {
        bellmanFord();
        for (int nd = 1; nd <= n; nd++) {
            int len = edges[nd].size();
            for (int i = 0; i < len; i++) {
                int nxt = edges[nd][i];
                ntwrk[nd][nxt].cst = minDist[nd] + ntwrk[nd][nxt].cst - minDist[nxt];
            }
        }
    }

    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) {
                    if (flow[curr.nd][dest] != ntwrk[curr.nd][dest].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;
            flow[son][father[son]] -= minFlow;
            cstPth += minFlow * ntwrk[father[son]][son].cst;
            son = father[son];
        }
        cstPth -= minDist[dest] * minFlow;
        maxflow += minFlow;
        return cstPth;
    }
    int solveNetwork() {
        maxflow = 0;
        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, {0, -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;
}