【HNOI2013】切糕

题面

题解

新建第\(R + 1\)层,将切点换成割边,然后就出现了最小割模型

然后从源点\(S\)向第一层的每个点连一条容量为\(\infty\)的边,从第\(R + 1\)层的每个点向汇点\(T\)连一条容量为\(\infty\)的边,这些边不会被割掉。

首先不考虑\(D\)的限制,从\((i, j, k) \to (i, j, k + 1)\)连一条容量为\(val[i][j][k]\)的边。

然后考虑\(D\)的限制,假设\((i, j)\)\((k, l)\)是相邻的,那么我们要让\(f(i, j) - f(k, l) > D\)时也能有从\(S \to T\)的流,

那么从\((i, j, z)\)\((k, l, z - D)\)连一条容量为\(\infty\)的边就可以了

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);

inline int read()
{
    int data = 0, w = 1; char ch = getchar();
    while(ch != '-' && (!isdigit(ch))) ch = getchar();
    if(ch == '-') w = -1, ch = getchar();
    while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    return data * w;
}

const int maxn(250010), maxm(1000000), N(45), INF(0x3f3f3f3f);
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};

int P, Q, R, D, idcnt;
int val[N][N][N];
int id[N][N][N];

struct edge { int next, to, cap; } e[maxm];
int head[maxn], e_num = -1, S, T;

inline void add_edge(int from, int to, int cap)
{
    e[++e_num] = (edge) {head[from], to, cap}; head[from] = e_num;
    e[++e_num] = (edge) {head[to], from,  0 }; head[to]   = e_num;
}

int q[maxn], tail, lev[maxn], cur[maxn];
int bfs()
{
    memset(lev, 0, sizeof lev); q[tail = lev[S] = 1] = S;
    for(RG int i = 1; i <= tail; i++)
    {
        int x = q[i];
        for(RG int j = head[x]; ~j; j = e[j].next)
        {
            int to = e[j].to;
            if(lev[to] || (!e[j].cap)) continue;
            q[++tail] = to, lev[to] = lev[x] + 1;
        }
    }
    return lev[T];
}

int dfs(int x, int f)
{
    if(x == T || (!f)) return f;
    int ans = 0, cap;
    for(RG int &i = cur[x]; ~i; i = e[i].next)
    {
        int to = e[i].to;
        if(e[i].cap && lev[to] == lev[x] + 1)
        {
            cap = dfs(to, std::min(f - ans, e[i].cap));
            e[i].cap -= cap, e[i ^ 1].cap += cap, ans += cap;
            if(ans == f) break;
        }
    }
    if(!ans) lev[x] = 0;
    return ans;
}

inline int Dinic()
{
    int ans = 0;
    while(bfs())
    {
        for(RG int i = S; i <= T; i++) cur[i] = head[i];
        ans += dfs(S, INF);
    }
    return ans;
}

int main()
{
    memset(head, -1, sizeof head); S = ++idcnt;
    P = read(), Q = read(), R = read(), D = read();
    for(RG int k = 1; k <= R; k++)
        for(RG int i = 1; i <= P; i++)
            for(RG int j = 1; j <= Q; j++)
                val[i][j][k] = read();
    for(RG int i = 1; i <= P; i++)
        for(RG int j = 1; j <= Q; j++)
            for(RG int k = 1; k <= R + 1; k++)
                id[i][j][k] = ++idcnt;
    T = ++idcnt;
    for(RG int i = 1; i <= P; i++)
        for(RG int j = 1; j <= Q; j++)
            add_edge(S, id[i][j][1], INF),
            add_edge(id[i][j][R + 1], T, INF);
    for(RG int i = 1; i <= P; i++)
        for(RG int j = 1; j <= Q; j++)
            for(RG int k = 1; k <= R; k++)
                add_edge(id[i][j][k], id[i][j][k + 1], val[i][j][k]);
    for(RG int i = 1; i <= P; i++)
        for(RG int j = 1; j <= Q; j++)
            for(int d = 0; d < 4; d++)
            {
                int tx = dx[d] + i, ty = dy[d] + j;
                if(tx < 1 || tx > P || ty < 1 || ty > Q) continue;
                for(RG int k = D + 1; k <= R + 1; k++)
                    add_edge(id[i][j][k], id[tx][ty][k - D], INF);
            }
    printf("%d\n", Dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cj-xxz/p/10395951.html