此处有图:传送门!!不过图好像左右画反了。。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
",ans);
return 0;
}