zoukankan      html  css  js  c++  java
  • bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流

     

    2756:[SCOI2012]奇怪的游戏

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 4926  Solved: 1362
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output


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

    Sample Input

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

    Sample Output

    2
    -1

    HINT

    【数据范围】 

        对于30%的数据,保证  T<=10,1<=N,M<=8 

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

     

    Source

     

    对棋盘进行黑白染色
    设黑格个数为num1 数值和为sum1
    设白格个数为num1 数值和为sum1

    设最后都变为x

    num1 * x – sum1 = num2 * x – sum2
    x = (sum1 – sum2) / (num1 – num2)
    当num1 ≠ num2时 可以解出 x 再用网络流check即可

    对于num1 = num2时 可以发现 对于一个合法的x k>=x都是一个合法的解
    因为num1 = num2 => (num1 + num2) % 2 == 0 可以构造一层的满覆盖
    所以可以二分x 然后用网络流check

    建图:
    如果点k为白
    建边(s, k, x – v[k])
    如果为黑
    建边(k, t, x – v[k])
    对相邻点u、v (u为白)
    建边 (u, v, inf)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 
      7 #define inf (1LL<<50)
      8 #define pa pair<int,int>
      9 #define ll long long 
     10 #define p(x,y) (x-1)*m+y
     11 using namespace std;
     12 int read()
     13 {
     14     int x=0,f=1;char ch=getchar();
     15     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     16     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     17     return x*f;
     18 }
     19 
     20 ll s0,s1;
     21 int c0,c1;
     22 int test,n,m,cnt,S,T;
     23 int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};
     24 int a[45][45];
     25 int last[2005],h[2005],q[2005],cur[2005];
     26 bool color[45][45];
     27 struct edge{
     28     int to,next;ll v;
     29 }e[20005];
     30 
     31 void insert(int u,int v,ll w)
     32 {
     33     e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
     34     e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=0;
     35 }
     36 bool bfs()
     37 {
     38     int head=0,tail=1;
     39     memset(h,-1,sizeof(h));
     40     q[0]=S;h[S]=0;
     41     while(head!=tail)
     42     {
     43         int now=q[head];head++;
     44         for(int i=last[now];i;i=e[i].next)
     45             if(e[i].v&&h[e[i].to]==-1)
     46             {
     47                 h[e[i].to]=h[now]+1;
     48                 q[tail++]=e[i].to;
     49             }
     50     }
     51     return h[T]!=-1;
     52 }
     53 ll dfs(int x,ll f)
     54 {
     55     if(x==T)return f;
     56     ll w,used=0;
     57     for(int i=cur[x];i;i=e[i].next)
     58         if(h[e[i].to]==h[x]+1)
     59         {
     60             w=dfs(e[i].to,min(f-used,e[i].v));
     61             e[i].v-=w;e[i^1].v+=w;
     62             if(e[i].v)cur[x]=i;
     63             used+=w;if(used==f)return f;
     64         }
     65     if(!used)h[x]=-1;
     66     return used;
     67 }
     68 ll dinic()
     69 {
     70     ll tmp=0;
     71     while(bfs())
     72     {
     73         for(int i=S;i<=T;i++)cur[i]=last[i];
     74         tmp+=dfs(S,inf);
     75     }
     76     return tmp;
     77 }
     78 bool check(ll x)
     79 {
     80     memset(last,0,sizeof(last));
     81     cnt=1;S=0;T=n*m+1;
     82     ll tot=0;
     83     for(int i=1;i<=n;i++)
     84         for(int j=1;j<=m;j++)
     85             if(color[i][j])
     86             {
     87                 insert(S,p(i,j),x-a[i][j]);tot+=x-a[i][j];
     88                 for(int k=0;k<4;k++)
     89                 {
     90                     int nowx=i+xx[k],nowy=j+yy[k];
     91                     if(nowx<1||nowy<1||nowx>n||nowy>m)continue;
     92                     insert(p(i,j),p(nowx,nowy),inf);
     93                 }
     94             }
     95             else insert(p(i,j),T,x-a[i][j]);
     96     if(dinic()==tot)return 1;
     97     return 0;
     98 }
     99 int main()
    100 {
    101     test=read();
    102     while(test--)
    103     {
    104         c0=c1=s0=s1=0;
    105         n=read();m=read();
    106         int mx=0;
    107         for(int i=1;i<=n;i++)
    108             for(int j=1;j<=m;j++)
    109             {
    110                 a[i][j]=read(),color[i][j]=(i+j)&1;
    111                 mx=max(mx,a[i][j]);
    112             }
    113         for(int i=1;i<=n;i++)
    114             for(int j=1;j<=m;j++)
    115                 if(color[i][j])s1+=a[i][j],c1++;
    116                 else s0+=a[i][j],c0++;
    117         if(c0!=c1)
    118         {
    119             ll x=(s0-s1)/(c0-c1);
    120             if(x>=mx)
    121                 if(check(x))
    122                 {
    123                     printf("%lld
    ",x*c1-s1);
    124                     continue;
    125                 }
    126             puts("-1");
    127         }
    128         else
    129         {
    130             if(s0!=s1)
    131             {
    132                 puts("-1");
    133                 continue;
    134             }
    135             ll l=mx,r=inf;
    136             while(l<=r)
    137             {
    138                 ll mid=(l+r)>>1;
    139                 if(check(mid))r=mid-1;
    140                 else l=mid+1;
    141             }
    142             printf("%lld
    ",(ll)l*c1-s1);
    143         }
    144     }   
    145 }
  • 相关阅读:
    10-02 青蛙跳台阶(斐波那契数列的应用)
    10-01 斐波那契数列
    08 二叉树的下一个节点
    07 重建二叉树
    Java中如何调用静态方法
    Java中如何调用静态方法
    Java方法调用数组,是否改变原数组元素的总结
    Java方法调用数组,是否改变原数组元素的总结
    JAVA中,一个类中,方法加不加static的区别,
    JAVA中,一个类中,方法加不加static的区别,
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8682436.html
Copyright © 2011-2022 走看看