zoukankan      html  css  js  c++  java
  • 刷题总结——奇怪的游戏(scoi2012)

    题目:

    题目描述

    Blinker 最近喜欢上一个奇怪的游戏。
    这个游戏在一个 N*M  的棋盘上玩,每个格子有一个数。每次 Blinker  会选择两个相邻的格子,并使这两个数都加上 1。
    现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出 -1。

    输入格式

    输入的第一行是一个整数 T,表示输入数据有T 轮游戏组成。
    每轮游戏的第一行有两个整数 N 和 M , 分别代表棋盘的行数和列数。
    接下来有 N 行,每行 M 个数。 

    输出格式

    对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出 -1。

    样例数据 1

    输入  [复制]

     

    2 2 
    1 2 
    2 3 
    3 3 
    1 2 3 
    2 3 4 
    4 3 2

    输出


    -1

    备注

     【数据范围】
    对于 30% 的数据,保证 T<=10,1<=N,M<=8
    对于 100% 的数据,保证 T<= 10,1<=N,M<=40,所有数为正整数且小于 1000000000 

    题解:

      这里引用http://www.cnblogs.com/DaD3zZ-Beyonder/p/5765882.html:

      一道比较有趣的题目

      先对题目进行分析:

      首先我们考虑对棋盘黑白染色,那么我们发现:“每次相邻两个+1”,显然是一黑一白+1

      那么我们先统计出WhiteNum,BlackNum(黑白点的数目),WhiteSum,BlackSum(黑白点初始权值和)(接下来可能用Wn,Ws,Bn,Bs代替)

      那么对于一次增加,显然是WhiteSum+1,BlackSum+1

      考虑对最后的情况进行讨论:

      那么很显然,当WhiteNum==BlackNum时(即总点数为偶数)

      如果WhiteSum!=BlackSum,显然无解

      如果WhiteSum==BlackSum时,我们发现,对于X如果成立,那么X+1一定成立,显然满足二分的性质,那么二分这个值,进行判定

      当WhiteNum!=BlackNum时(即总点数为奇数)

      发现显然,若有解,则解唯一,那么直接验证正确性即可

      至于解怎么求?

      设最后所有数变为X,易得X*Wn-Ws=X*Bn-Bs,整理下可得:X=(Ws-Bs)/(Wn-Bn),用网络流验证即可

      那么考虑建图:

      S-->白点,约束为X-val[i][j]

      黑点-->T,约束为X-val[i][j]

      相邻的白点-->黑点,约束为INF

      判断是否满流即可

      最后说下个人心得:

      这道题的重点其实不是网络流,而是黑白染色这一想法,由相邻格子染色其实可以考虑到这一点,以后做到相似的题要注意这一想法····然后就是后面的分类讨论···也是由黑白染色后考虑答案的性质得出的·····这是一道很好的题,染色+二分+网络流;

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=2010;
    const int M=1001000;
    const long long inf=1e+18;
    int Ri()
    {
      char c; 
      int f=0;
      for(c=getchar();c<'0'||c>'9';c=getchar());
      for(;c<='9'&&c>='0';c=getchar())
        f=(f<<3)+(f<<1)+c-'0';
      return f;
    }
    long long Rl()
    {
      char c; 
      long long f=0;
      for(c=getchar();c<'0'||c>'9';c=getchar());
      for(;c<='9'&&c>='0';c=getchar())
        f=f*10+c-'0';
      return f;
    }
    int T,n,m,tot,first[N],cur[N],lev[N],next[M],go[M],Wn,Bn,src,des;
    int color[N][N],num[N][N];
    long long map[N][N],rest[M],Ws,Bs,ans,sum;
    inline void comb(int a,int b,long long c)
    {
      next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c;
      next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0;
    }
    inline bool bfs()
    {
      for(int i=src;i<=des;i++)  cur[i]=first[i],lev[i]=-1;
      static int que[N],tail,u,v;
      que[tail=1]=src;
      lev[src]=0;
      for(int head=1;head<=tail;head++)
      {
        u=que[head];
        for(int e=first[u];e;e=next[e])
        {
          if(lev[v=go[e]]==-1&&rest[e])
          {
            lev[v]=lev[u]+1;
            que[++tail]=v;
            if(v==des)  return true;
          }
        }
      }
      return false;
    }
    inline long long dinic(int u,long long flow)
    {
      if(u==des)
        return flow;
      long long res=0,delta;
      int v;
      for(int &e=cur[u];e;e=next[e])
      {
        if(lev[v=go[e]]>lev[u]&&rest[e])
        {
          delta=dinic(v,min(flow-res,rest[e]));
          if(delta)
          {
            rest[e]-=delta;
            rest[e^1]+=delta;
            res+=delta;
            if(res==flow)  break;
          }
        }
      }
      if(flow!=res)  lev[u]=-1;
      return res;
    }
    inline long long maxflow()
    {
      long long temp=0;
      while(bfs())
        temp+=dinic(src,inf);
      return temp;
    }
    inline bool jud(int x,int y)
    {
      return x>=1&&x<=n&&y>=1&&y<=m;
    }
    inline bool check(long long lim)
    {
      tot=1;
      memset(first,0,sizeof(first));
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {  
          if(
          !color[i][j])
            comb(src,num[i][j],lim-map[i][j]);
          else
            comb(num[i][j],des,lim-map[i][j]);
        }
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
          if(!color[i][j])
          {
            if(jud(i-1,j))
              comb(num[i][j],num[i-1][j],inf);
            if(jud(i+1,j))
              comb(num[i][j],num[i+1][j],inf);
            if(jud(i,j-1))
              comb(num[i][j],num[i][j-1],inf);
            if(jud(i,j+1))
              comb(num[i][j],num[i][j+1],inf);
          }
      long long temp=maxflow();
      if(temp==((long long)Wn*lim-Ws))
        return true;
      else return false;
    }
    inline void solve()
    {
      Wn=Ws=Bn=Bs=0;
      src=0;
      des=n*m+1;
      int cnt=0;
      long long left=0,right=1e+18;
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {  
          num[i][j]=++cnt;
          color[i][j]=(i+j)%2;
          if(!color[i][j])
            Wn++,Ws+=map[i][j];
          else
            Bn++,Bs+=map[i][j];
          left=max(left,map[i][j]);
        }
      if(Wn==Bn)
      {
        if(Ws!=Bs)  
        {
          cout<<"-1"<<endl;
          return;
        }
        else
        {
          while(left<=right)
          {
            long long mid=(left+right)/2;
            if(check(mid))  ans=mid,right=mid-1;
            else left=mid+1;
          }
          cout<<ans*Wn-Ws<<endl;
        }
      }
      else
      {
        ans=(long long)(Ws-Bs)/(Wn-Bn);
        if(ans<left)
        {
          cout<<"-1"<<endl;
          return;
        }
        
        if(check(ans))  
        {
          cout<<ans*Wn-Ws<<endl;
          return;
        }
        else  cout<<"-1"<<endl;
      }
    }
    int main()
    {
     // freopen("a.in","r",stdin);
      T=Ri();
      while(T--)
      {
        n=Ri(),m=Ri();
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
            map[i][j]=Rl();
        solve();
      }
      return 0;
    }
  • 相关阅读:
    mysql修改数据库的存储引擎(InnoDB)
    如何查看进程/服务是否启动
    Spark Streaming 入门
    Graphlab create的基本使用
    构建房屋预测回归模型
    构建应用深层特征的图像检索系统
    构建商品评价的分类器
    Elastic Static初识(01)
    《Linux就该这么学》笔记(二)
    《Linux就该这么学》笔记(一)
  • 原文地址:https://www.cnblogs.com/AseanA/p/7464908.html
Copyright © 2011-2022 走看看