Luogu P3227 [HNOI2013]切糕 最小割

首先推荐一个写的很好的题解,个人水平有限只能写流水账,还请见谅。

经典的最小割模型,很多人都说这个题是水题,但我还是被卡了=_=

技巧:加边表示限制

在没有距离\(<=d\)的限制时候,我们对每个竖轴连一条完整的边跑最小割即可(效果和取\(min\)是一样的)。但是现在需要加入这个限制,我们就要考虑加边。

原条件:\(|x - y| <= d\)

转化为:\(x - y <= d\)\(y - x <= d\)

我们考虑对每一个不等式单独处理,实际上可以转化为:

对于每一个\(x\),和它四联通的所有\(y\)都满足\(y >= x - d\)

这个不等式的限制如何满足?我们考虑添加\(x_h -> y_{h - d}\)。比如如果\(d\)\(2\)的话:

来源:⚡cdecl⚡ 的博客

图中如果可以在在\(x\)上和\(y\)上割掉两条边,那么一定有\(y >= x - 2\),因为割掉\(y < x - 2\)的边并不能完全割断原图,所以没有意义。

那么我们就对每个\(x\)向其四联通的位置这样连边就可以了。

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

const int N = 200010;
const int M = 400010;
const int INF = 0x3f3f3f3f;

int n, m, h, d, cnt = -1, head[N];
int mv[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

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

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;
}

bool in_map (int x, int y, int z) {
    return 1 <= x && x <= n && 1 <= y && y <= m && 1 <= z && z <= h;
}

int inn (int x, int y, int z) {return n * m * h * 0 + (x - 1) * m * h + (y - 1) * h + z;}
int out (int x, int y, int z) {return n * m * h * 1 + (x - 1) * m * h + (y - 1) * h + z;}

queue <int> q;
int cur[N], deep[N];

bool bfs (int s, int t) {
    memcpy (cur, head, sizeof (head));
    memset (deep, 0x3f, sizeof (deep));
    q.push (s); deep[s] = 0;
    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;
}

int main () {
    memset (head, -1, sizeof (head));
    cin >> n >> m >> h >> d;
    int s = n * m * h * 2 + 1;
    int t = n * m * h * 2 + 2;
    int _val = 0;
    for (int z = 1; z <= h; ++z) {
        for (int x = 1; x <= n; ++x) {
            for (int y = 1; y <= m; ++y) {
                cin >> _val;
                add_len (inn (x, y, z), out (x, y, z), _val);
                if (in_map (x, y, z + 1)) {
                    add_len (out (x, y, z), inn (x, y, z + 1), INF); 
                }
                for (int i = 0; i < 4; ++i) {
                    int tx = x + mv[i][0];
                    int ty = y + mv[i][1];
                    if (in_map (tx, ty, z - d)) {
                        add_len (out (x, y, z), inn (tx, ty, z - d), INF);
                    }
                }
            }
        }
    }
    for (int x = 1; x <= n; ++x) {
        for (int y = 1; y <= m; ++y) {
            add_len (s, inn (x, y, 1), INF);
            add_len (out (x, y, h), t, INF);
        }
    }
    cout << Dinic (s, t) << endl;
}
posted @ 2019-04-01 09:38  maomao9173  阅读(148)  评论(0编辑  收藏  举报