这个题是个挺经典的最小割。
这个题的关键是如何限制h之差不超过d。首先我们按高度分层,每层的点向下一层相同位置的点连边,边权设为点权(也就是说我们要多设一层),然后如果我们割掉这条边就意味着选择了下面这个点。然后,对于h之差的限制,我们把k+d层的点向k层的四周的点连+oo边,也就是说如果我们割掉了一条边,就不能选择+oo的边连接的上面的边,因为选择了这条边,如果再选择上面的边的话,就不能构成割了,因为流还是可以经过那条+oo的边流回来。其实类比一下最大权独立集的话,这条+oo的边的意义就是选了某个点以后,就不能选和它相差超过d的点了。
最后跑最小割就ok了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 80000 7 #define maxm 3000000 8 #define inf 2147483647 9 using namespace std; 10 struct et 11 { 12 int s,t,val,next; 13 }e[maxm]; 14 const int dx[4]={0,1,0,-1}; 15 const int dy[4]={1,0,-1,0}; 16 int fir[maxn],dis[maxn],gap[maxn],last[maxn]; 17 int v,s[60][60][60]; 18 int st,ed,n,m,h,num,tot,D,cnt; 19 20 int dfs(int now,int flow) 21 { 22 if (now==ed) return flow; 23 int sap=0; 24 for (int j=last[now];j;j=e[j].next) 25 { 26 int k=e[j].t; 27 if (e[j].val&&dis[now]==dis[k]+1) 28 { 29 last[now]=j; 30 int tmp=dfs(k,min(e[j].val,flow-sap)); 31 e[j].val-=tmp; 32 e[j^1].val+=tmp; 33 sap+=tmp; 34 if (sap==flow) return sap; 35 } 36 } 37 if (dis[st]>=num) return sap; 38 if (!(--gap[dis[now]])) dis[st]=num; 39 ++gap[++dis[now]]; 40 last[now]=fir[now]; 41 return sap; 42 } 43 44 void add(int x,int y,int z) 45 { 46 e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].next=fir[x]; fir[x]=tot; 47 e[++tot].s=y; e[tot].t=x; e[tot].val=0; e[tot].next=fir[y]; fir[y]=tot; 48 } 49 50 int main() 51 { 52 //freopen("cake.in","r",stdin); 53 //freopen("cake.out","w",stdout); 54 scanf("%d%d%d",&n,&m,&h); 55 scanf("%d",&D); 56 for (int k=1;k<=h+1;k++) 57 for (int i=1;i<=n;i++) 58 for (int j=1;j<=m;j++) 59 s[k][i][j]=++cnt; 60 st=0; ed=cnt+1; num=cnt+2; tot=1; 61 for (int i=1;i<=n;i++) 62 for (int j=1;j<=m;j++) 63 add(st,s[1][i][j],inf),add(s[h+1][i][j],ed,inf); 64 for (int k=1;k<=h;k++) 65 for (int i=1;i<=n;i++) 66 for (int j=1;j<=m;j++) 67 scanf("%d",&v),add(s[k][i][j],s[k+1][i][j],v); 68 for (int k=1;k<=h;k++) 69 for (int i=1;i<=n;i++) 70 for (int j=1;j<=m;j++) 71 for (int p=0;p<4;p++) 72 if (s[k+D][i+dx[p]][j+dy[p]]) 73 add(s[k+D][i+dx[p]][j+dy[p]],s[k][i][j],inf); 74 //for (int i=1;i<=tot;i++) cout<<e[i].s<<' '<<e[i].t<<' '<<e[i].val<<endl; 75 memset(dis,0,sizeof(dis)); 76 memset(gap,0,sizeof(gap)); 77 gap[0]=num; 78 for (int i=st;i<=ed;i++) last[i]=fir[i]; 79 int ans=0; 80 while (dis[st]<num) ans+=dfs(st,inf); 81 printf("%d\n",ans); 82 return 0; 83 }