Cod sursa(job #1993791)

Utilizator alexpetrescuAlexandru Petrescu alexpetrescu Data 23 iunie 2017 19:17:02
Problema Flux maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.69 kb
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

#define INF 1000000000

#define MAXN 350
#define MASK 511
#define MAXM 25000

FILE *fin = fopen("fmcm.in", "r"), *fout = fopen("fmcm.out", "w");

int care[MAXN + 1];

struct myc {
    int x, y, z;
    myc(int _x, int _y, int _z) {
        x = _x;
        y = _y;
        z = _z;
    }
};

class fmcmDirected {
    int s, d, k, ans, rez;
    int f[MAXM], c[MAXM];
    std::vector <myc> g[MAXN];
    bool viz[MAXN];
    int q[MASK + 1], dist[MAXN];
    int heap[MAXN], poz[MAXN];
    int from[MAXN], cine[MAXN];
    int dp[MAXN], real[MAXN];

  public :

    inline void initialize(int n) {
        s = k = ans = rez = 0;
        d = n;
    }

    inline void add(int x, int y, int z, int t) {
        muchie(x, y, z, t);
        muchie(y, x, 0, -t);
    }

    inline void flood(){
        bellman();
        while (dijkstra())
            go();
    }

    inline int flux() {
        return ans;
    }

    inline int cost() {
        return rez;
    }

  private :

    inline void muchie(int x, int y, int z, int t) {
        f[k] = 0;
        c[k] = z;
        g[x].push_back(myc(y, t, k));
        k++;
    }

    inline void bellman() {
        for (int i = s; i <= d; i++)
            dist[i] = INF;
        memset(viz, 0, sizeof(bool) * (d + 1));
        int st = 0, dr = 1;
        dist[s] = 0;
        viz[s] = 1;

        while (st < dr) {
            int x = q[st & MASK];
            viz[x] = 0;
            st++;

            for (auto &y : g[x]) {
                if (c[y.z] > f[y.z] && dist[x] + y.y < dist[y.x]) {
                    dist[y.x] = dist[x] + y.y;
                    if(viz[y.x] == 0) {
                        viz[y.x] = 1;
                        q[dr & MASK] = y.x;
                        dr++;
                    }
                }
            }
        }
    }

    inline bool cmp(int a, int b) {
        return dp[a] < dp[b];
    }

    inline int tata(int p) {
        return (p - 1) / 2;
    }

    inline int fiust(int p) {
        return 2 * p + 1;
    }

    inline int fiudr(int p) {
        return 2 * p + 2;
    }

    inline void mySwap(int p, int q) {
        int aux = heap[p];
        heap[p] = heap[q];
        heap[q] = aux;
        poz[heap[p]] = p;
        poz[heap[q]] = q;
    }

    inline void urcare(int p) {
        int tad;
        while (p > 0 && cmp(heap[p], heap[tata(p)])) {
            tad = tata(p);
            mySwap(p, tad);
            p = tad;
        }
    }

    inline void coborare(int p) {
        int q;
        bool f = 1;
        while(f && (q = fiust(p)) <= d) {
            if(fiudr(p) <= d && cmp(heap[fiudr(p)], heap[q]))
                q = fiudr(p);
            if(cmp(heap[q], heap[p])) {
                mySwap(p, q);
                p = q;
            }else f = 0;
        }
    }

    inline bool dijkstra() {
        for (int i = s; i <= d; i++)
            heap[i] = poz[i] = i;
        for (int i = s; i <= d; i++)
            dp[i] = INF;
        memset(viz, 0, sizeof(bool) * (d + 1));

        dp[s] = 0;
        while (dp[heap[0]] != INF) {
            int x = heap[0];
            for (auto &y : g[x]) {
                if (viz[y.x] == 0 && c[y.z] > f[y.z] && dp[x] + y.y + dist[x] - dist[y.x] < dp[y.x]) {
                    from[y.x] = x;
                    cine[y.x] = y.z;
                    real[y.x] = real[x] + y.y;
                    dp[y.x] = dp[x] + y.y + dist[x] - dist[y.x];
                    urcare(poz[y.x]);
                }
            }
            dp[x] = INF;
            viz[x] = 1;
            coborare(0);
        }

        for (int i = s; i <= d; i++)
            dist[i] = real[i];

        return viz[d];
    }

    inline void go() {
        int x = d, r = INF;
        while (x != s) {
            r = std::min(r, c[cine[x]] - f[cine[x]]);
            x = from[x];
        }
        x = d;
        while (x != s) {
            f[cine[x]] += r;
            f[1 ^ cine[x]] -= r;
            x = from[x];
        }

        ans += r;
        rez += r * real[d];
    }
}T;

int main() {
    int n, m, s, d;
    fscanf(fin, "%d%d%d%d", &n, &m, &s, &d);

    care[s] = 0;
    care[d] = n - 1;
    int q = 0;
    for (int i = 1; i <= n; i++)
        if (i != s && i != d)
            care[i] = ++q;

    T.initialize(n - 1);

    for (int i = 0; i < m; i++) {
        int x, y, z, t;
        fscanf(fin, "%d%d%d%d", &x, &y, &z, &t);

        T.add(care[x], care[y], z, t);
    }

    T.flood();

    fprintf(fout, "%d\n", T.cost());

    fclose(fin);
    fclose(fout);
    return 0;
}