如果没有第二个要求的话,直接把每一个 f(x,y) 的取值建图求最小割。加上这个要求,就需要连一些不能割掉的边来保证相邻的格子割掉的边不能太远。
#include<cstdio>
#include<algorithm>
using namespace std;
const int s=200005,t=200006,oo=0x3f3f3f3f;
int fir[200010],ne[4000010],to[4000010],w[4000010],que[200010],dep[200010],
id[45][45][45],xx[]={1,-1,0,0},yy[]={0,0,1,-1},
p,q,r,d,num,tot;
void add(int u,int v,int x)
{
num++;
ne[num*2]=fir[u];
fir[u]=num*2;
to[num*2]=v;
w[num*2]=x;
ne[num*2+1]=fir[v];
fir[v]=num*2+1;
to[num*2+1]=u;
w[num*2+1]=0;
}
bool ok(int x,int y)
{
return x>=1&&x<=p&&y>=1&&y<=q;
}
bool bfs()
{
int hd=1,tl=1,u,v;
for (int i=1;i<=tot;i++) dep[i]=0;
dep[t]=0;
dep[que[1]=s]=1;
while (hd<=tl)
{
u=que[hd++];
for (int i=fir[u];i;i=ne[i])
if (w[i]&&!dep[v=to[i]])
{
dep[v]=dep[u]+1;
que[++tl]=v;
}
}
return dep[t];
}
int dfs(int u,int lim)
{
if (u==t) return lim;
int v,ret=0,x;
for (int i=fir[u];i;i=ne[i])
if (w[i]&&dep[v=to[i]]==dep[u]+1)
{
x=dfs(v,min(w[i],lim-ret));
w[i]-=x;
w[i^1]+=x;
ret+=x;
}
if (!ret) dep[u]=0;
return ret;
}
void check()
{
for (int i=1;i<=t;i++)
for (int j=fir[i];j;j=ne[j])
if (w[j])
printf("%d->%d:%d\n",i,to[j],w[j]);
}
int main()
{
int x,x1,y1,ans=0;
scanf("%d%d%d%d",&p,&q,&r,&d);
for (int k=0;k<=r;k++)
for (int i=1;i<=p;i++)
for (int j=1;j<=q;j++)
id[i][j][k]=++tot;
for (int k=1;k<=r;k++)
for (int i=1;i<=p;i++)
for (int j=1;j<=q;j++)
{
scanf("%d",&x);
add(id[i][j][k-1],id[i][j][k],x);
if (k>=d)
for (int l=0;l<4;l++)
if (ok(x1=i+xx[l],y1=j+yy[l]))
add(id[i][j][k],id[x1][y1][k-d],oo);
}
for (int i=1;i<=p;i++)
for (int j=1;j<=q;j++)
{
add(s,id[i][j][0],oo);
add(id[i][j][r],t,oo);
}
/*check();*/
while (bfs()) ans+=dfs(s,oo);
printf("%d\n",ans);
}