[bzoj3144][网络流-最小割]切糕

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;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/80052682