zoukankan      html  css  js  c++  java
  • BZOJ3144: [Hnoi2013]切糕

    BZOJ3144: [Hnoi2013]切糕

    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

    题解Here!

    乍一看,这题不是计算几何吗?

    然后发现,最小值怎么算?

    网络流!

    把切点看作割边。

    新建一个虚拟的层R+1,建立超级源汇点S,T。

    先考虑没有光滑限制怎么做。

    先由源点S向第1层的每一个点连一条边,再由第R+1层的每一个点向汇点T连一条边,这些边是割不掉的,所以容量都为MAX。

    然后对于任何一个1<= i<= P,1<= j<= Q,1<= k<= R,由 ( i , j , k )向 ( i , j , k+1 )连一条流量为 val[ i ][ j ][ k ] 的不和谐值的边。

    显然,对于任何一个1<= i<= P,1<= j<= Q,从 ( i , j , 1 ) 到 ( i , j , R+1 ) 的路径上需要且只需要割掉一条边。

    再考虑加上光滑限制。

    可以发现对于任意一个在同一平面上距离为1的两个点对 ( i , j ),( x , y ),其实只要限制 f( i , j ) - f( x , y ) <= D 就可以了。

    因为如果有存在 f( i , j ) - f( x , y ) <= D ,那么一定有 f( x , y ) - f( i , j ) > D ,自然不符合条件。

    怎样限制这个条件呢?

    可以发现,我们的目标其实就是让 f( i , j ) - f( x , y ) > D 时,S仍然可以到达T。

    也就是对于任意一个在同一平面上距离为1的两个点对 ( i , j ),( x , y ) ,对于任何一个D+1 <= k <= R+1,由 ( i , j , k ) 向 ( x , y , k-D ) 连一条流量为MAX的割不掉的边。

    最后求最小割即为答案。

    最小割==最大流,直接Dinic。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 300010
    #define MAXM 50
    #define MAX 999999999
    using namespace std;
    const int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1};
    int n,m,p,d,s,t,c=2;
    int head[MAXN],deep[MAXN],val[MAXM][MAXM][MAXM];
    struct node{
        int next,to,w;
    }a[MAXN<<1];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    inline void add(int u,int v,int w){
        a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
        a[c].to=u;a[c].w=0;a[c].next=head[v];head[v]=c++;
    }
    bool bfs(){
        int u,v;
        queue<int> q;
        for(int i=s;i<=t;i++)deep[i]=0;
        deep[s]=1;
        q.push(s);
        while(!q.empty()){
            u=q.front();
            q.pop();
            for(int i=head[u];i;i=a[i].next){
                v=a[i].to;
                if(a[i].w&&!deep[v]){
                    deep[v]=deep[u]+1;
                    if(v==t)return true;
                    q.push(v);
                }
            }
        }
        return false;
    }
    int dfs(int x,int limit){
        if(x==t)return limit;
        int v,sum,cost=0;
        for(int i=head[x];i;i=a[i].next){
            v=a[i].to;
            if(a[i].w&&deep[v]==deep[x]+1){
                sum=dfs(v,min(a[i].w,limit-cost));
                if(sum>0){
                    a[i].w-=sum;
                    a[i^1].w+=sum;
                    cost+=sum;
                    if(limit==cost)break;
                }
                else deep[v]=-1;
            }
        }
        return cost;
    }
    int dinic(){
        int ans=0;
        while(bfs())ans+=dfs(s,MAX);
        return ans;
    }
    void work(){
        printf("%d
    ",dinic());
    }
    void init(){
        int u,v,w;
        n=read();m=read();p=read();d=read();
        s=1;t=n*m*(p+1)+2;
        for(int k=1;k<=p;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        val[i][j][k]=read();
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            u=(i-1)*m+j+1;
            add(s,u,MAX);
            for(int k=1;k<=p;k++)add(n*m*(k-1)+u,n*m*k+u,val[i][j][k]);
            add(n*m*p+u,t,MAX);
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        for(int l=0;l<4;l++){
            u=i+fx[l];v=j+fy[l];
            if(u<1||u>n||v<1||v>m)continue;
            for(int k=d+1;k<=p+1;k++)add((n*m*(k-1)+m*(i-1)+j+1),n*m*(k-d-1)+m*(u-1)+v+1,MAX);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 翻硬币 反转(开关问题)
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 高僧斗法 博弈论
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 格子刷油漆
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9417256.html
Copyright © 2011-2022 走看看