题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3144
【分析】
所有人都说这是个经典的最小割模型......蒟蒻泪流满面......
建一个r+1层的,每层都是p*q的图,从源出发向第一层连inf的边,从第r+1层上每个点出发向汇连inf的边,对i,j,k与i,j,k+1之间连v(i,j,k)的边。
如果没有高度限制,那么这么做就是在每一条纵轴上选一个点。
因为有高度限制,所以对于每个层数大于d的点,要向x,y坐标相邻的,层数小d的点连一条inf的边。
以p=1,q=2,r=5,d=2为例。(先忽略从右边较高的点连向左边较低的点的那些边)
下面是源,上面是汇。如图所示,如果我把图中的红边割掉,那么图中的蓝边也就没有用了。如果此时把绿边割掉,那么还是存在一条从源到汇的路径;如果割绿色的边上面的边,那么源到汇就没有路径可达了。
仔细理解一下,也就是在左边选了一条边以后,右边的高度小于当前边的边就不能选了。如果把右上向左下连的边也连起来,那么高度就完全限制住了。
然后跑一下最大流就好了。
【代码】
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxl=45,maxn=75000,maxm=maxn<<4,inf=~0U>>1,mov[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int head[maxn],next[maxm],E[maxm],F[maxm],Ecnt;
int id[maxl][maxl][maxl];
int p,q,r,d;
int s,e;
inline void Add_Edge(int x,int y,int f) {next[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;F[Ecnt]=0;next[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;F[Ecnt]=f;}
void Init()
{
scanf("%d%d%d%d",&p,&q,&r,&d);
int cnt=0,x;
Ecnt=1;
s=++cnt;
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;
e=++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],e,inf);
#define nx (j+mov[mv][0])
#define ny (k+mov[mv][1])
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 mv=0;mv<4;mv++)
if (id[i][nx][ny])
Add_Edge(id[i][j][k],id[i-d][nx][ny],inf);
#undef nx
#undef ny
}
int Q[maxn],Vis[maxn],h[maxn];
bool BFS(int time)
{
int top=1,tail=1;
Q[1]=s;Vis[1]=time;h[1]=0;
while (top<=tail)
{
int x=Q[top++],hx=h[x];
for (int i=head[x];i;i=next[i]) if (Vis[E[i]]!=time && F[i^1])
h[E[i]]=h[x]+1,Vis[E[i]]=time,Q[++tail]=E[i];
if (Vis[e]==time) break;
}
return Vis[e]==time;
}
int DFS(int x,int f)
{
if (x==e) return f;
int res=f;
for (int i=head[x];i && res;i=next[i]) if (h[E[i]]==h[x]+1 && F[i^1])
{
int d=DFS(E[i],min(F[i^1],res));
res-=d;F[i]+=d;F[i^1]-=d;
}
if (f==res) h[x]=-1;
return f-res;
}
void Dinic()
{
int res=0,time=0;
while (BFS(++time)) res+=DFS(s,inf);
printf("%d\n",res);
}
int main()
{
Init();
Dinic();
return 0;
}