zoukankan      html  css  js  c++  java
  • 【BZOJ3144】切糕(HNOI2013)-最小割

    测试地址:切糕
    做法:本题需要用到最小割。
    每个坐标上选一个高度,我们可以把一个坐标拆成R+1个点组成的顺次相连的链,中间的边权为原来的点权,然后从源点连向每条链的链头,从每条链的链尾连到汇点。
    当我们切掉一条边,表示我们选择这条边表示的高度。那么怎么体现相邻坐标高度之差不超过D这个限制呢?我们知道这个条件等价于对于每个坐标,如果取了高度h,那么相邻坐标不能取高度hD及以下。我们采取的建模方式是,从代表高度h的边的起点连一条容量为正无穷的边,连到相邻坐标代表高度hD的边的起点。那么如果我们相邻坐标上选择割高度低于hD的边,源点到汇点间就有一条路径,这就不是一个割了。对于这个图求一个最小割即可。可以证明,最小割中不会割同一个坐标上的两条或以上的边。
    我傻逼的地方:学了那么久网络流,今天居然第一次听说有当前弧优化这种东西……果然学习还是要细致,不能偷工减料。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,p,q,r,d,S,T;
    int first[100010]={0},tot=1;
    int h,t,Q[100010],lvl[100010],cur[100010];
    struct edge
    {
        int v,next,f;
    }e[500010];
    
    int point(int x,int y,int z)
    {
        return ((x-1)*q+y)*(r+1)+z-1;
    }
    
    void insert(int a,int b,int f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d%d%d",&p,&q,&r,&d); 
        n=point(p,q,r+1);
        S=n+1,T=n+2;
        for(int z=1;z<=r;z++)
            for(int x=1;x<=p;x++)
                for(int y=1;y<=q;y++)
                {
                    int a;
                    scanf("%d",&a);
                    insert(point(x,y,z),point(x,y,z+1),a);
                }
        for(int x=1;x<=p;x++)
            for(int y=1;y<=q;y++)
            {
                insert(S,point(x,y,1),inf);
                insert(point(x,y,r+1),T,inf);
                for(int z=d+1;z<=r+1;z++)
                {
                    if (x>1) insert(point(x,y,z),point(x-1,y,z-d),inf);
                    if (x<p) insert(point(x,y,z),point(x+1,y,z-d),inf);
                    if (y>1) insert(point(x,y,z),point(x,y-1,z-d),inf);
                    if (y<q) insert(point(x,y,z),point(x,y+1,z-d),inf);
                }
            }
        for(int i=1;i<=T;i++) cur[i]=first[i];
    }
    
    bool makelevel()
    {
        memset(lvl,-1,sizeof(lvl));
        lvl[S]=0;
        h=t=1;
        Q[1]=S;
        while(h<=t)
        {
            int v=Q[h++];
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&lvl[e[i].v]==-1)
                {
                    lvl[e[i].v]=lvl[v]+1;
                    Q[++t]=e[i].v;
                }
        }
        for(int i=1;i<=T;i++)
            cur[i]=first[i];
        return lvl[T]!=-1;
    }
    
    int maxflow(int v,int maxf)
    {
        int ret=0,f;
        if (v==T) return maxf;
        for(int i=cur[v];i;i=e[i].next)
        {
            if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
            {
                f=maxflow(e[i].v,min(maxf-ret,e[i].f));
                ret+=f;
                e[i].f-=f;
                e[i^1].f+=f;
                if (ret==maxf) break;
            }
            cur[v]=i; 
        } 
        if (!ret) lvl[v]=-1;
        return ret;
    }
    
    void dinic()
    {
        int maxf=0;
        while(makelevel())
            maxf+=maxflow(S,inf);
        printf("%d",maxf);
    }
    
    int main()
    {
        init();
        dinic();
    
        return 0;
    }
  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793449.html
Copyright © 2011-2022 走看看