BZOJ3144 [Hnoi2013]切糕 【最小割】

题目

这里写图片描述

输入格式

第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。
100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。

输出格式

仅包含一个整数,表示在合法基础上最小的总不和谐值。

输入样例

2 2 2

1

6 1

6 1

2 6

2 6

输出样例

6

提示

最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1

题解

论一类最小割模型:

有P * Q个纵列,每列选一个点,且相邻纵列之间的点距离不超过D,求选点最小值

我们将每一列所有点向其下一个点连边【这时候多加上额外的一层点】,容量为其权值,这样由最小割,每一类都会选择一条边割去,就意味着选了这条边入度的点
这里写图片描述

为了满足相邻距离不超过D的限制,我们对(x,y,z)向相邻的(x’,y’,z - D)连边INF,使得在选择(x,y,z)后必须选择(x’,y’,z - D)以上的点,如图
这里写图片描述

如此建图,跑最大流

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define cls(x) memset(x,0,sizeof(x))
#define p(x,y,z) ((z - 1) * P * Q + (x - 1) * Q + y)
using namespace std;
const int maxn = 100000,maxm = 3000005,INF = 1000000000;
inline int RD(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    return out * flag;
}
int P,Q,R,D;
int h[maxn],ne = 0,cur[maxn],d[maxn],vis[maxn],S,T;
struct EDGE{int to,f,nxt;}ed[maxm];
inline void build(int u,int v,int w){
    ed[ne] = (EDGE){v,w,h[u]}; h[u] = ne++;
    ed[ne] = (EDGE){u,0,h[v]}; h[v] = ne++;
}
bool bfs(){
    for (int i = S; i <= T; i++) vis[i] = d[i] = 0;
    queue<int> q;
    d[S] = 0; vis[S] = true; q.push(S); int u,to;
    while (!q.empty()){
        u = q.front(); q.pop();
        Redge(u) if (ed[k].f && !vis[to = ed[k].to]){
            d[to] = d[u] + 1; vis[to] = true; q.push(to);
        }
    }
    return vis[T];
}
int dfs(int u,int minf){
    if (u == T || !minf) return minf;
    int flow = 0,f,to;
    if (cur[u] == -2) cur[u] = h[u];
    for (int& k = cur[u]; k != -1; k = ed[k].nxt)
        if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
            ed[k].f -= f; ed[k ^ 1].f += f;
            minf -= f; flow += f;
            if (!minf) break;
        }
    return flow;
}
int maxflow(){
    int flow = 0;
    while (bfs()){
        for (int i = S; i <= T; i++) cur[i] = -2;
        flow += dfs(S,INF);
    }
    return flow;
}
int X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0};
int main(){
    memset(h,-1,sizeof(h));
    P = RD(); Q = RD(); R = RD(); D = RD(); S = 0; T = P * Q * (R + 1) + 1;
    int v;
    REP(x,P) REP(y,Q) build(S,p(x,y,1),INF),build(p(x,y,R + 1),T,INF);
    REP(z,R) REP(x,P) REP(y,Q){
        v = RD();
        build(p(x,y,z),p(x,y,z + 1),v);
        if (z - D > 0){
            for (int k = 0; k < 4; k++){
                int nx = x + X[k],ny = y + Y[k];
                if (nx < 1 || ny < 1 || nx > P || ny > Q) continue;
                build(p(x,y,z),p(nx,ny,z - D),INF);
            }
        }
    }
    printf("%d",maxflow());
    return 0;
}
posted @ 2018-01-14 11:38  Mychael  阅读(213)  评论(0编辑  收藏  举报