zoukankan      html  css  js  c++  java
  • bzoj 3144: [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

    Source

    论学好语文的重要性,真的看不懂这个题目在说什么,这个人的切法真的是清新脱俗。。。

    先把题目翻译一下:

    有一个p*q的矩阵,每个位置上的格子上可以选r个数字中的一个填,每选一个数字都会有一个费用,并且相邻的格子上的数字相差不超过d,

    求把每个格子填完数后的最小费用;

    首先不考虑相差不超过d的限制,是一个经典的最小割模型:

    每个点有n种选择,用s->x1->x2->x3->x4->T,如果割掉x1->x2的边,表示选择了x2,把图画出来的话很容易懂

    然后考虑d的限制,用的是Inf限制不合法决策的方法(是最小割中常用技巧)

    对于每个点加入选了k,那么该点的k向周围的点的k-d连Inf,周围点的k+d+1向该点的k+1连Inf的边,

    把图画出来之后判断要如何割边才能使S-->T连通,可以把不合法的割边中增加Inf的流量从而使该决策不会被选为最小割中;

    玄学剪枝真重要

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #define RG register
    using namespace std;
    typedef long long ll;
    const int N=300050;
    const int Inf=19260817;
    int gi(){
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int id[50][50][50],f[50][50][50],p,q,r,d,tt,S,T;
    int mx[5]={1,-1,0,0},my[5]={0,0,1,-1};
    int head[N],to[N],nxt[N],level[N],s[N],cnt=1,F,Q[N*5];
    void Addedge(int x,int y,int z) {
      to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
    }
    void lnk(int x,int y,int z){
      Addedge(x,y,z),Addedge(y,x,0);
    }
    inline bool bfs(){
      for(RG int i=S;i<=T;i++) level[i]=0;
      Q[0]=S,level[S]=1;int t=0,sum=1;
      while(t<sum){
        int x=Q[t++];
        if(x==T) return 1;
        for(RG int i=head[x];i;i=nxt[i]){
          int y=to[i];
          if(s[i]&&level[y]==0){
    	level[y]=level[x]+1;
    	Q[sum++]=y;
          }
        }
      }
      return 0;
    }
    inline int dfs(RG int x,int maxf){
      if(x==T) return maxf;
      int ret=0;
      for(RG int i=head[x];i;i=nxt[i]){
        int y=to[i],f=s[i];
        if(level[y]==level[x]+1&&f){
          int minn=min(f,maxf-ret);
          f=dfs(y,minn);
          s[i]-=f,s[i^1]+=f,ret+=f;
          if(ret==maxf) break;
        }
      }
      if(!ret) level[x]=0;
      return ret;
    }
    void Dinic(){
      while(bfs()) F+=dfs(S,Inf);
    }
    int main(){
      freopen("cake.in","r",stdin);
      freopen("cake.out","w",stdout);
      p=gi(),q=gi(),r=gi(),d=gi();
      for(int i=1;i<=r;i++)
        for(int j=1;j<=p;j++)
          for(int k=1;k<=q;k++){
    	f[j][k][i]=gi(),id[j][k][i]=++tt;
          }
      S=0,T=++tt;
      for(int i=1;i<=p;i++)
        for(int j=1;j<=q;j++){
          lnk(S,id[i][j][1],f[i][j][1]);
          for(int k=1;k<r;k++) lnk(id[i][j][k],id[i][j][k+1],f[i][j][k+1]);
          lnk(id[i][j][r],T,Inf);
          for(int k=0;k<4;k++){
    	int x=i+mx[k],y=j+my[k];
    	if(1<=x&&x<=p&&1<=y&&y<=q){
    	  for(int z=1;z<=r;z++){
    	    int zz=z-d,zzz=z+d+1;
    	    if(1<=zz&&zz<=r) lnk(id[i][j][z],id[x][y][zz],Inf);
    	    if(1<=zzz&&zzz<=r) lnk(id[x][y][zzz],id[i][j][z+1],Inf);
    	  }
    	}
          }
        }
      Dinic();printf("%d
    ",F);
      return 0;
    }
  • 相关阅读:
    安装VMWare tools 及安装后/mnt中有hgfs但没共享文件的解决办法
    linux挂载命令
    RHEL7/CentOS7 Network Service开机无法启动的解决方法
    linux消息队列编程实例
    Linux进程间通信——使用消息队列
    消息队列函数
    ipcs查看消息队列命令
    linux批量删除
    HTTP 请求消息头部实例:
    drf 序列化组件
  • 原文地址:https://www.cnblogs.com/qt666/p/6980071.html
Copyright © 2011-2022 走看看