Description
Input
第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个
矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。
100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。
Output
仅包含一个整数,表示在合法基础上最小的总不和谐值。
Sample Input
2 2 2
1
6 1
6 1
2 6
2 6
Sample Output
6
HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
题解
哇考试的时候居然没有想到这样搞最小割。。
YY了一个一定满流的最小割= =
对于每一个纵轴,每一个点向他上面的点连边,流量为下面那个点的不和谐值
对于一个高度为i的点,向他四周的高度为i-D的点连边,流量INF
st向底面每个点连边,流量INF
顶面每个点(扩展一个面)向ed连边,流量INF
跑最小割即可
设想一下,割掉纵轴上一条边就相当于选了这个点,那么他到另外四周的相对高度>D的点会被割掉,不然就还有增广路可流
这里的假设是选的这个点是较高的,如果选的是较低的话也是同理,因为另外一个点也可以这样考虑呀
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int dx[4]={0,-1,0,1};
const int dy[4]={-1,0,1,0};
struct node
{
int x,y,c,next,other;
}a[810000];int len,last[210000];
void ins(int x,int y,int c)
{
int k1,k2;
k1=++len;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
k2=++len;
a[len].x=y;a[len].y=x;a[len].c=0;
a[len].next=last[y];last[y]=len;
a[k1].other=k2;
a[k2].other=k1;
}
int h[110000],head,tail;
int list[2110000],st,ed;
bool bt_h()
{
list[1]=st;head=1;tail=2;
memset(h,0,sizeof(h));h[st]=1;
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(a[k].c>0 && h[y]==0)
{
h[y]=h[x]+1;
list[tail++]=y;
}
}
head++;
}
if(h[ed]==0)return false;
return true;
}
int findflow(int x,int f)
{
if(x==ed)return f;
int s=0,t;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(h[y]==h[x]+1 && a[k].c>0 && s<f)
{
s+=(t=findflow(y,min(a[k].c,f-s)));
a[k].c-=t;a[a[k].other].c+=t;
}
}
if(s==0)h[x]=0;
return s;
}
int P,Q,R,D;
bool chk(int x,int y){if(x>=1 && x<=P && y>=1 && y<=Q)return true;return false;}
int val[45][45][45];
int pt(int x,int y,int z){return (z-1)*P*Q+(x-1)*Q+y;}
int main()
{
// freopen("d.in","r",stdin);
// freopen("d.out","w",stdout);
scanf("%d%d%d",&P,&Q,&R);
scanf("%d",&D);
st=P*Q*(R+1)+1;ed=P*Q*(R+1)+2;
for(int i=1;i<=R;i++)
for(int j=1;j<=P;j++)
for(int k=1;k<=Q;k++)scanf("%d",&val[j][k][i]),ins(pt(j,k,i),pt(j,k,i+1),val[j][k][i]);
for(int i=D+1;i<=R;i++)
for(int j=1;j<=P;j++)
for(int k=1;k<=Q;k++)
for(int l=0;l<=3;l++)
if(chk(j+dx[l],k+dy[l]))
ins(pt(j,k,i),pt(j+dx[l],k+dy[l],i-D),999999999);
for(int i=1;i<=P;i++)for(int j=1;j<=Q;j++)ins(st,pt(i,j,1),999999999),ins(pt(i,j,R+1),ed,999999999);
int ans=0;
while(bt_h())ans+=findflow(st,99999999);
printf("%d\n",ans);
return 0;
}