[HNOI2013] 切糕

此处有图:传送门!!不过图好像左右画反了。。emmm

理解一下这样建图的效用:设在一个纵(竖)轴上割开的点高度是h(建图是已经当边处理了,所以多搞了一层点。。),那么最小割一定不会在这根纵轴的相邻轴出再割掉一个高度小于h-d的边。这就保证了题目中"对于所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,则|f(x,y)-f(x’,y’)| ≤D,其中 D 是给定的一个非负整数"的要求。

真是一个经典的最小割模型呢

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

const int N=7e5+10;
const int L=2e6+10;
const int inf=0x3f3f3f3f;

int S=N-1,T=N-2;
int head[N],to[L],upp[L],last[L],cnt=1;
int que[N],lev[N],hd,tl;

inline void add_edge(int x,int y,int u1,int u2=0) {
    to[++cnt]=y,upp[cnt]=u1,last[cnt]=head[x],head[x]=cnt;
    to[++cnt]=x,upp[cnt]=u2,last[cnt]=head[y],head[y]=cnt; 
}
inline bool bfs() {
    memset(lev,0,sizeof lev);
    lev[S]=1;
    que[hd=0,tl=1]=S;
    while(hd<tl) {
        int x=que[++hd];
        for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && !lev[to[i]]) 
            lev[to[i]]=lev[x]+1, que[++tl]=to[i];
    }
    return lev[T]!=0;
}
int dfs(int x,int tf) {
    if(x==T) return tf;
    int tot=0,tmp;
    for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && lev[x]+1==lev[to[i]]) {
        tmp=dfs(to[i],min(tf-tot,upp[i]));
        if(tmp) upp[i]-=tmp,upp[i^1]+=tmp,tot+=tmp;
        if(tot==tf) break;
    }
    if(!tot) lev[x]=-1;
    return tot;
}

int p,q,r,d;
int id[50][50][50];

const int fx[]={-1,1,0,0};
const int fy[]={0,0,-1,1};

int main() {
    scanf("%d%d%d%d",&p,&q,&r,&d);
    int cnt=0, x;
    for(int i=1; i<=r+1; ++i) {
        for(int j=1; j<=p; ++j) {
            for(int k=1; k<=q; ++k) {
                id[i][j][k]=++cnt;
            }
        }
    }
    for(int i=1; i<=r; ++i) {
        for(int j=1; j<=p; ++j) {
            for(int k=1; k<=q; ++k) {
                scanf("%d",&x);
                add_edge(id[i][j][k],id[i+1][j][k],x);
            }
        }
    }
    for(int i=1; i<=p; ++i) {
        for(int j=1; j<=q; ++j) {
            add_edge(S,id[1][i][j],inf);
            add_edge(id[r+1][i][j],T,inf);
        }
    }
    for(int i=d+1; i<=r+1; ++i) {
        for(int j=1; j<=p; ++j) {
            for(int k=1; k<=q; ++k) {
                for(int x,y,t=0; t<4; ++t) {
                    if(id[x=j+fx[t]][y=k+fy[t]]) {
                        add_edge(id[i][j][k],id[i-d][x][y],inf);
                    }
                }
            }
        }
    }
    int ans=0;
    while(bfs()) ans+=dfs(S,inf);
    printf("%d\n",ans);
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/nosta/p/10174728.html