zoukankan      html  css  js  c++  java
  • 【BZOJ 2756】[SCOI2012]奇怪的游戏 二分+最大流

    这道题提醒我,要有将棋盘黑白染色的意识,尤其是看到相邻格子这样的条件的时候,然后就是要用到与其有关的性质与特点以体现其作用,这道题就是用到了黑格子与白格子之间的关系进行的,其出发点是每次一定会给一个黑格子与一个白格子均加一,那么最后黑白格子所加量相同(最关键的地方)。
    然后呢,还要观察,最终高度与行动次数一一对应,于是求解他们两个是等效的,然后发现如果最后高度确定,是很好验证是否可行的,就是方格下水道。进一步分析,当黑格与白格的数量不同那么最终高度一定,可以一下判解。当数量相同的时候关于最终高度是单调的,因为h可以,h+1也可以,所以这道题就这么解决了。
    为什么我想不到啊(苣蒻++)。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define pos(a,b) (((a)-1)*m+(b))
    typedef long long LL;
    const int N=42;
    const int P=N*N;
    const int E=P*10;
    const LL Inf=0x3f3f3f3f3f3f3f3fLL;
    struct V{
      int to,next;
      LL f;
    }c[E];
    int head[P],t;
    inline void add(int x,int y,LL z){
      c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].f=z;
    }
    inline void clear(){
      memset(head,0,sizeof(head)),t=1;
    }
    int n,m;
    int S,T;
    int deep[P],q[P],front,back;
    inline bool bfs(){
      memset(deep,0,sizeof(deep));
      front=back=0,q[back++]=S,deep[S]=1;
      while(front!=back){
        int x=q[front++];
        for(int i=head[x];i;i=c[i].next)
          if(c[i].f&&deep[c[i].to]==0){
            deep[c[i].to]=deep[x]+1;
            if(c[i].to==T)return true;
            q[back++]=c[i].to;
          }
      }return false;
    }
    inline LL dfs(int x,LL v){
      if(x==T||v==0)return v;
      LL ret=0;
      for(int i=head[x];i;i=c[i].next)
        if(c[i].f&&deep[c[i].to]==deep[x]+1){
          LL f=dfs(c[i].to,std::min(c[i].f,v));
          ret+=f,v-=f,c[i].f-=f,c[i^1].f+=f;
          if(v==0)break;
        }
      if(ret==0)deep[x]=0;
      return ret;
    }
    int cnt[2];
    LL sum[2];
    int max,val[N][N];
    inline LL dinic(){
      LL ret=0;
      while(bfs())ret+=dfs(S,Inf);
      return ret;
    }
    inline bool check(LL ans){
      clear();LL ret=0;
      for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
          if((i+j)&1){
            if(i>1)
              add(pos(i,j),pos(i-1,j),Inf),add(pos(i-1,j),pos(i,j),0);
            if(j>1)
              add(pos(i,j),pos(i,j-1),Inf),add(pos(i,j-1),pos(i,j),0);
            if(i<n)
              add(pos(i,j),pos(i+1,j),Inf),add(pos(i+1,j),pos(i,j),0);
            if(j<m)
              add(pos(i,j),pos(i,j+1),Inf),add(pos(i,j+1),pos(i,j),0);
            add(S,pos(i,j),ans-val[i][j]),add(pos(i,j),S,0);
            ret+=ans-val[i][j];
          }else
            add(pos(i,j),T,ans-val[i][j]),add(T,pos(i,j),0);
      return ret==dinic();
    }
    inline void work1(){
      if((sum[0]-sum[1])%(cnt[0]-cnt[1])!=0){
        puts("-1");return;
      }
      LL ans=(sum[0]-sum[1])/(cnt[0]-cnt[1]);
      if(check(ans))
        printf("%lld
    ",(ans*n*m-(sum[0]+sum[1]))>>1LL);
      else puts("-1");
    }
    inline void work2(){
      if(sum[0]!=sum[1]){
        puts("-1");return;
      }
      LL l=max,r=Inf/5000LL,mid,ans=0;
      while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))
          ans=mid,r=mid-1;
        else
          l=mid+1;
      }
      if(ans==0)puts("-1");
      else printf("%lld
    ",(ans*n*m-(sum[0]+sum[1]))>>1LL);
    } 
    int main(){
      int test;scanf("%d",&test);
      while(test--){
        scanf("%d%d",&n,&m);
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        max=0,S=n*m+1,T=n*m+2;
        for(int i=1;i<=n;++i)
          for(int j=1;j<=m;++j){
            scanf("%d",&val[i][j]);
            ++cnt[(i+j)&1],sum[(i+j)&1]+=val[i][j];
            max=std::max(max,val[i][j]);
          }
        if(cnt[0]!=cnt[1])work1();
        else work2();
      }return 0;
    }
  • 相关阅读:
    Interesting Finds: 2008.09.15~2008.09.21
    Interesting Finds: 2008.10.05~2008.10.07
    Interesting Find: 2008.10.02
    Interesting Finds: 2008.10.13~2008.10.15
    Interesting Finds: 2008.09.29
    Interesting Finds: 2008.10.08~2008.10.09
    Interesting Finds: 2008.09.22~2008.09.27
    Interesting Finds: 2008.10.12
    Interesting Finds: 2008.10.16~2008.10.18
    9月27号
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8024773.html
Copyright © 2011-2022 走看看