您的位置:首页 > 其它

BZOJ 3144 切糕(最小割)

2014-06-20 17:14 148 查看
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3144

题意:



思路:我们假设没有那个D的限制。这样就简
单了。贪心的话,我们只要在每一个纵轴上选择最小值即可。若看做最小割,我们可以从每一层的(x,y,z)向上一层的(x,y,z+1)连边流量为
v(x,y,z),这样就是增加一层R+1。然后原点向第一层连边,第R+1层向汇点连边。这样就是一个最小割,其实跟上面的贪心是一样的。现在有了D的
限制,我们看看怎么将这个限制加入到现在建好的网络流图中。我们将(x,y,z)向(x,y,z-D)这个格子四周的格子连边正无穷就OK了。这样当我们
选择了某边(x,y,z)到(x,y,z+1)的边时,比如在(x+1,y)

这个轴上我们就不能选择(x+1,y,z-D-1)和(x+1,y,z-D)这条边以及以下的边,因为(x,y,z)向(x+1,y,z-D)有边,因此
构不成割。

struct node
{
int v,cap,next;
};

node edges[N*5];
int head
,e;

void add(int u,int v,int cap)
{
edges[e].v=v;
edges[e].cap=cap;
edges[e].next=head[u];
head[u]=e++;
}

void Add(int u,int v,int cap)
{
add(u,v,cap);
add(v,u,0);
}

int cur
,h
,num
,pre
;

int Maxflow(int s,int t,int n)
{
int i;
for(i=0;i<=n;i++) h[i]=num[i]=0,cur[i]=head[i];
int u=s,ans=0,Min,k,x;
while(h[u]<n)
{
if(u==t)
{
Min=INF+1;
for(i=s;i!=t;i=edges[cur[i]].v)
{
x=cur[i];
if(edges[x].cap<Min) Min=edges[x].cap,k=i;
}
ans+=Min; u=k;
for(i=s;i!=t;i=edges[cur[i]].v)
{
x=cur[i];
edges[x].cap-=Min;
edges[x^1].cap+=Min;
}
}
for(i=cur[u];i!=-1;i=edges[i].next)
{
if(edges[i].cap>0&&h[u]==1+h[edges[i].v])
{
break;
}
}
if(i!=-1)
{
cur[u]=i;
pre[edges[i].v]=u;
u=edges[i].v;
}
else
{
if(--num[h[u]]==0) break;
cur[u]=head[u];
x=n;
for(i=head[u];i!=-1;i=edges[i].next)
{
k=edges[i].v;
if(edges[i].cap>0&&h[k]<x) x=h[k];
}
h[u]=x+1;
num[x+1]++;
if(u!=s) u=pre[u];
}
}
return ans;
}

int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int s,t,n,m,K,d;
int a[55][55][55];

int OK(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m;
}

int main()
{
RD(n,m,K); RD(d);
int i,j,k,x=0;
FOR1(i,K+1) FOR1(j,n) FOR1(k,m) a[i][j][k]=++x;
s=0; t=++x;
clr(head,-1);
FOR1(i,n) FOR1(j,m)
{
Add(s,a[1][i][j],INF);
Add(a[K+1][i][j],t,INF);
}
FOR1(i,K) FOR1(j,n) FOR1(k,m)
{
RD(x);
Add(a[i][j][k],a[i+1][j][k],x);
}
FOR1(i,K) if(i-d>=1) FOR1(j,n) FOR1(k,m)
{
FOR0(x,4) if(OK(j+dx[x],k+dy[x]))
{
Add(a[i][j][k],a[i-d][j+dx[x]][k+dy[x]],INF);
}
}
PR(Maxflow(s,t,t+1));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: