最小割 [HNOI 2013]切糕

时间:2021-09-13 04:28:14

     传送门

     读了好久才看懂题。在这个p,q,r的长方体里,每个纵轴选一个点,共有p*q个,相邻的格点纵坐标不相差d。

      把点权下放到边。S->第一层->第二层……->第R层->T(边权就是刚才下放的点权)

       但是又有了那个平滑度,可以向他周围四个位置比它低d层的点建一个流量为inf的边,就可以保证。

      

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#define inf 100000000
using namespace std;
int p,q,r,v[45][45][45],d,id[45][45][45],cnt,e=2;
int S=0,T,adj[100000],dep[100000],g[4][2]={0,1,1,0,0,-1,-1,0};
struct node
{
int v,next,l;
} a[2000000];
void add(int u,int v,int l)
{
a[e].v=v;a[e].l=l;a[e].next=adj[u];adj[u]=e++;
a[e].v=u;a[e].l=0;a[e].next=adj[v];adj[v]=e++;
}
int bfs()
{
memset(dep,0,sizeof(dep));
queue<int> q;
q.push(S);
dep[S]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=adj[x];i;i=a[i].next)
{
int to=a[i].v;
if(!dep[to]&&a[i].l)
{
dep[to]=dep[x]+1;
q.push(to);
if(to==T)return 1;
}
}
}
return 0;
}
int dfs(int x,int len)
{
if(x==T)return len;
int tmp=len,k;
for(int i=adj[x];i;i=a[i].next)
{
int to=a[i].v;
if(tmp&&a[i].l&&dep[to]==dep[x]+1)
{
k=dfs(to,min(a[i].l,tmp));
if(!k)
{
dep[to]=0;
continue;
}
a[i].l-=k;
a[i^1].l+=k;
tmp-=k;
}
}
return len-tmp;
}
int yjn()
{
freopen("nutcake.in","r",stdin);
freopen("nutcake.out","w",stdout);
scanf("%d%d%d%d",&p,&q,&r,&d);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++)
scanf("%d",&v[i][j][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++)
{
if(i==1)
add(S,id[i][j][k],v[i][j][k]);
else
add(id[i-1][j][k],id[i][j][k],v[i][j][k]);
if(i==r)
add(id[i][j][k],T,inf);
if(i>d)
{
for(int l=0;l<=3;l++)
{
int x=j+g[l][0],y=k+g[l][1];
if(x<1||x>p||y<1||y>q)continue;
add(id[i][j][k],id[i-d][x][y],inf);
}
}
}
int ans=0;
while(bfs())
ans+=dfs(S,inf);
cout<<ans;
}
int qty=yjn();
int main(){;}