1. 程式人生 > >P4177 [CEOI2008]order 網絡流,最小割,最大權閉合子圖

P4177 [CEOI2008]order 網絡流,最小割,最大權閉合子圖

problem pre cli www 最大 同時 oid pan org

題目鏈接 \(Click\) \(Here\)

如果沒有租用機器就是一個裸的最大權閉合子圖。現在有了租用機器應該怎麽辦呢?

單獨拆點是不行的,因為會和直接買下的情況脫離關系,租借是和連邊直接相關的,那麽就可以考慮在邊上下功夫。我們把從工程到機器的連邊從\(INF\)變成租用費用,這樣再跑最大權閉合子圖,就可以同時考慮租用費用了。如果租用費用過高就會割斷(選用)購買機器的費用,反之亦然。

#include <bits/stdc++.h>
using namespace std;

const int N = 2410;
const int M = 4000010;
const int INF = 0x3f3f3f3f;

struct Graph {
    int cnt, head[N];

    struct edge {
        int nxt, to, f;
    }e[M];

    void Init () {
        cnt = -1;
        memset (head, -1, sizeof (head));
    }

    void add_len (int u, int v, int f) {
        e[++cnt] = (edge) {head[u], v, f}; head[u] = cnt;
        e[++cnt] = (edge) {head[v], u, 0}; head[v] = cnt;
    }

    queue <int> q;
    int cur[N], deep[N];
    
    bool bfs (int s, int t) {
        memcpy (cur, head, sizeof (head));
        memset (deep, 0x3f, sizeof (deep));
        deep[s] = 0; q.push (s);
        while (!q.empty ()) {
            int u = q.front (); q.pop ();
            for (int i = head[u]; ~i; i = e[i].nxt) {
                int v = e[i].to;
                if (deep[v] == INF && e[i].f) {
                    deep[v] = deep[u] + 1;
                    q.push (v);
                }
            }
        }
        return deep[t] != INF;
    }

    int dfs (int u, int t, int lim) {
        if (u == t || !lim) return lim;
        int tmp = 0, flow = 0;
        for (int &i = cur[u]; ~i; i = e[i].nxt) {
            int v = e[i].to;
            if (deep[v] == deep[u] + 1) {
                tmp = dfs (v, t, min (lim, e[i].f));
                lim -= tmp;
                flow += tmp;
                e[i ^ 0].f -= tmp;
                e[i ^ 1].f += tmp;
                if (!lim) break;
            }
        }
        return flow;
    }
    
    int Dinic (int s, int t) {
        int min_cut = 0;
        while (bfs (s, t)) {
            min_cut += dfs (s, t, INF);
        }
        return min_cut;
    }
}G;

int n, m;

int A (int x) {return n * 0 + x;}
int B (int x) {return n * 1 + x;}

int main () {
    //freopen ("data.in", "r", stdin);
    cin >> n >> m; G.Init ();
    int s = N - 1, t = N - 2, ans = 0;
    for (int i = 1; i <= n; ++i) {
        static int w, k, p, r;
        cin >> w >> k; ans += w;
        G.add_len (s, A (i), w); //get_val = w
        for (int j = 1; j <= k; ++j) {
            cin >> p >> r;
            G.add_len (A (i), B (p), r); //rent cost = r
        }
    }
    for (int i = 1; i <= m; ++i) {
        static int w; cin >> w;
        G.add_len (B (i), t, w);
    }
    cout << ans - G.Dinic (s, t) << endl;
}

P4177 [CEOI2008]order 網絡流,最小割,最大權閉合子圖