代价拆点做一个最小割
/**************************************************************
Problem: 3144
User: Clare
Language: C++
Result: Accepted
Time:904 ms
Memory:14304 kb
****************************************************************/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 70000
#define INF 0x3f3f3f3f
int n,m,S,T,p,q,r,D;
long long Ans,sum;
struct Edge{
int to,next,value;
}edge[1000000];
int head[N],tot=1;
int dis[N],cur[N],A[50][50][50];
int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};
queue<int> Q;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Addedge(int u,int v,int w)
{
tot++;edge[tot].next=head[u];edge[tot].to=v;edge[tot].value=w;head[u]=tot;
tot++;edge[tot].next=head[v];edge[tot].to=u;edge[tot].value=0;head[v]=tot;
}
int Po(int x,int y,int z)
{
if(z==0)
return 0;
else return (z-1)*p*q+(x-1)*q+y;
}
bool BFS()
{
memset(dis,-1,sizeof(dis));
dis[S]=0;Q.push(S);
while(!Q.empty())
{
int now=Q.front();Q.pop();
for(int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].value>0&&dis[v]<0)
{
dis[v]=dis[now]+1;
Q.push(v);
}
}
}
return dis[T]>0;
}
int Find(int k,int low)
{
if(k==T)
return low;
int qwer;
for(int i=cur[k];i;i=edge[i].next)
{
cur[k]=i;
int v=edge[i].to;
if(edge[i].value>0&&dis[v]==dis[k]+1&&(qwer=Find(v,min(low,edge[i].value))))
{
edge[i].value-=qwer;
edge[i^1].value+=qwer;
return qwer;
}
}
return 0;
}
void Dinic()
{
while(BFS())
{
for(int i=0;i<=T;i++)
cur[i]=head[i];
while(1)
{
int qwer=Find(S,INF);
if(qwer==0)
break;
else Ans+=qwer;
}
}
}
int main()
{
p=read();q=read();r=read();
D=read();
S=0;T=p*q*r+1;
for(int i=1;i<=r;i++)
{
for(int j=1;j<=p;j++)
{
for(int k=1;k<=q;k++)
A[j][k][i]=read();
}
}
for(int i=1;i<=p;i++)
{
for(int j=1;j<=q;j++)
{
for(int t=0;t<4;t++)
{
int nowx=i+xx[t],nowy=j+yy[t];
if(nowx<1||nowx>p||nowy<1||nowy>q)
continue;
for(int k=D+1;k<=r;k++)
{
Addedge(Po(i,j,k),Po(nowx,nowy,k-D),INF);
}
}
for(int k=1;k<=r;k++)
{
Addedge(Po(i,j,k-1),Po(i,j,k),A[i][j][k]);
}
Addedge(Po(i,j,r),T,INF);
}
}
Dinic();
cout<<Ans<<endl;
return 0;
}