传送门
最小割,主要考查建边的思路。本蒟蒻也是看了好几位大佬的博客才看懂。比如:
参考1
参考2
(x,y,z)连接(x,y,z+1)容量为f(x,y,z)
(x,y,z)连接(x’,y’,z-d)容量为inf,其中 (x,y)与(x’,y’)相邻
然后跑一边最小割即可。
注意!
立体图形的点编号不要写成
int num(int i,int j,int k) {
return (k-1)*n*m+(i-1)*n+j;
}
为什么呢?大概是因为有些不同位置的点可能会编出相同的编号。。。那整么办–先for一边打个时间戳tim,每次++即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=75000,INF=0x3f3f3f3f;
int dis[maxn],cur[maxn],head[maxn],edge=0,source,sink;
struct EDGE {
int v,r,nxt;
}e[400000];
int n,m,h,D,tim=0,c[42][42][42],val[42][42][42];
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
inline void adde(int u,int v,int r) {
e[edge].nxt=head[u],e[edge].v=v,e[edge].r=r,head[u]=edge++,
e[edge].nxt=head[v],e[edge].v=u,e[edge].r=0,head[v]=edge++;
}
inline bool bfs() {
queue<int> q;
memset(dis,-1,sizeof(dis)),dis[source]=0;
q.push(source);
while (!q.empty()) {
int p=q.front();q.pop();
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (e[i].r>0&&dis[v]==-1)
dis[v]=dis[p]+1,q.push(v);
}
}
return ~dis[sink];
}
int dfs(int p,int low) {
if (p==sink||low==0) return low;
int cost=0,flow;
for (int &i=cur[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (e[i].r>0&&dis[v]==dis[p]+1&&(flow=dfs(v,min(low,e[i].r)))) {
e[i].r-=flow,e[i^1].r+=flow,
cost+=flow,low-=flow;
if (low==0) return cost;
}
}
if (low>0) dis[p]=-1;
return cost;
}
int main() {
// freopen("bzoj 3144.in","r",stdin);
memset(head,-1,sizeof(head));
n=read(),m=read(),h=read(),D=read(),
source=0,sink=n*m*(h+1)+1;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
for (int k=1;k<=(h+1);++k)
c[i][j][k]=++tim;
++tim;//sink
for (int k=1;k<=h;++k)
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) {
val[i][j][k]=read();
adde(c[i][j][k],c[i][j][k+1],val[i][j][k]);
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) {
adde(source,c[i][j][1],INF),
adde(c[i][j][h+1],sink,INF);
for (int k=D+1;k<=h+1;++k) {
if (i+1<=n) adde(c[i][j][k],c[i+1][j][k-D],INF);
if (i-1>0) adde(c[i][j][k],c[i-1][j][k-D],INF);
if (j+1<=m) adde(c[i][j][k],c[i][j+1][k-D],INF);
if (j-1>0) adde(c[i][j][k],c[i][j-1][k-D],INF);
}
}
int min_cut=0;
while (bfs()) {
int a;
for (int i=source;i<=sink;++i) cur[i]=head[i];
while (a=dfs(source,INF)) min_cut+=a;
}
printf("%d\n",min_cut);
return 0;
}