• SCOI 2012 奇怪的游戏


    题目:http://61.187.179.132/JudgeOnline/problem.php?id=2756

    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 

     

    题解:

      给格子黑白染色后我们会发现,每次必定是把一个黑格子和一个白格子的值加1,那么就可以把两边给分开了。

     

      设白格子有num1个,数值和为sum1,黑格子有num2 个,数值和为sum2,设所有数最后都变成了x,那么有x*num1-sum1=x*num2-sum2,解之可得x=(sum1-sum2)/(num1-num2),当num1=num2即有偶数个格子时,此方程无意义,所以先说num1!=num2的情况。

     

      num1!=num2时,解出一个x,由于始终是把两个格子的值加1,所以若有解,x不可能小于所有值中的最大值且x必须是个整数,那么这样就只需检验当x满足上述两个条件时,是否可行即可了。

     

      num1=num2时,如果说都变成x可以实现,那么都变成x+1也能实现(做法是黑白格子两两配对后加1),所以可以二分最后变成的那个数即可(所操作的次数与x的大小是正相关的)。

     

      那么现在只需要检验当能否所有数都变成x,自然而然地就想到网络流了。总源向每个白格子连边,每个黑格子向总汇连边,流量为x减去该格子本来的权值,然后相邻的黑白格子连流量为无限大的边,求个最大流max_flow,并且提前算出若该方案可行需要多少步step,如果max_flow=step,则说明这是一个可行解,否则为不可行。

     

      网络流建议写非递归的,递归的跑起来有点慢(虽说应该不会有太大影响的,但我的递归的T了),然后左右界稍微卡好一点,不然也容易T。

     

      考试的时候已经把方法都想出来了,可是不知道又哪里写错了,再次崩掉。唉,还得努力攒RP啊……………………

     

    View Code
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<queue>
      5  
      6 using namespace std;
      7  
      8 const int maxw=41;
      9 const int maxn=1800;
     10 const int maxm=100000;
     11 const long long INF=123456789876ll;
     12  
     13 int n,m,en,d[maxn],s,e,stack[maxn];
     14  
     15 long long map[maxw][maxw];
     16  
     17 queue<int> que;
     18  
     19 struct edge
     20 {
     21     int e;
     22     long long f;
     23     edge *next,*op;
     24 }*v[maxn],ed[maxm],*p[maxn],*fe[maxn];
     25  
     26 void add_edge(int s,int e,long long f)
     27 {
     28     en++;
     29     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->f=f;
     30     en++;
     31     ed[en].next=v[e];v[e]=ed+en;v[e]->e=s;v[e]->f=0;
     32     v[s]->op=v[e];v[e]->op=v[s];
     33 }
     34  
     35 int get(int x,int y)
     36 {
     37     return (x-1)*m+y;
     38 }
     39  
     40 void get_add(int x,int y)
     41 {
     42     if (x>1) add_edge(get(x,y),get(x-1,y),INF);
     43     if (x<n) add_edge(get(x,y),get(x+1,y),INF);
     44     if (y>1) add_edge(get(x,y),get(x,y-1),INF);
     45     if (y<m) add_edge(get(x,y),get(x,y+1),INF);
     46 }
     47  
     48 bool bfs()
     49 {
     50     memset(d,-1,sizeof(d));
     51     d[s]=0;
     52     que.push(s);
     53     while (que.size())
     54     {
     55         int now=que.front();
     56         que.pop();
     57         for (edge *e=v[now];e;e=e->next)
     58             if (e->f && d[e->e]==-1)
     59             {
     60                 d[e->e]=d[now]+1;
     61                 que.push(e->e);
     62             }
     63     }
     64  
     65     return d[e]!=-1;
     66 }
     67  
     68 long long dfs(int now,long long cur_flow)
     69 {
     70     if (now==e) return cur_flow;
     71     long long rest=cur_flow;
     72     for (edge *e=v[now];e;e=e->next)
     73         if (e->f && d[e->e]==d[now]+1)
     74         {
     75             long long new_flow=dfs(e->e,min(rest,e->f));
     76             e->f-=new_flow;
     77             e->op->f+=new_flow;
     78             rest-=new_flow;
     79         }
     80     return cur_flow-rest;
     81 }
     82  
     83 long long agument()
     84 {
     85     int now,next,stop;
     86     long long delta,ans=0;
     87     for (int a=s;a<=e;a++)
     88         p[a]=v[a];
     89     stack[stop=1]=s;
     90     int t=e;
     91     while (stop>0)
     92     {
     93         now=stack[stop];
     94         if (now!=t)
     95         {
     96             for (;p[now];p[now]=p[now]->next)
     97                 if ((p[now]->f) && (d[now]+1==d[next=p[now]->e])) break;
     98             if (p[now])
     99             {
    100                 stack[++stop]=next;
    101                 fe[stop]=p[now];
    102             }
    103             else
    104             {
    105                 stop--;
    106                 d[now]=-1;
    107             }
    108         }
    109         else
    110         {
    111             delta=INF;
    112             for (int a=stop;a>=2;a--)
    113                 if (fe[a]->f<delta) delta=fe[a]->f;
    114             ans+=delta;
    115             for (int a=stop;a>=2;a--)
    116             {
    117                 fe[a]->f-=delta;
    118                 fe[a]->op->f+=delta;
    119                 if (fe[a]->f==0) stop=a-1;
    120             }
    121         }
    122     }
    123     return ans;
    124 }
    125  
    126 long long dinic()
    127 {
    128     long long ans=0;
    129     while (bfs())
    130         ans+=agument();
    131     return ans;
    132 }
    133  
    134 bool check(long long x)
    135 {
    136     en=0;
    137     memset(v,0,sizeof(v));
    138     s=0;
    139     e=n*m+1;
    140     long long flow=0;
    141     for (int a=1;a<=n;a++)
    142         for (int b=1;b<=m;b++)
    143         {
    144             if ((a+b)%2==0)
    145             {
    146                 add_edge(s,get(a,b),x-map[a][b]);
    147                 get_add(a,b);
    148             }
    149             else add_edge(get(a,b),e,x-map[a][b]);
    150             flow+=x-map[a][b];
    151         }
    152     long long ans=dinic();
    153     if (ans*2!=flow) return false;
    154     else return true;
    155 }
    156  
    157 long long gettime(long long x)
    158 {
    159     long long ans=0;
    160     for (int a=1;a<=n;a++)
    161         for (int b=1;b<=m;b++)
    162             ans+=x-map[a][b];
    163     return ans>>1;
    164 }
    165  
    166 int main()
    167 {
    168     freopen("game.in","r",stdin);
    169     freopen("game.out","w",stdout);
    170  
    171     int t;
    172     scanf("%d",&t);
    173     for (int z=1;z<=t;z++)
    174     {
    175         scanf("%d%d",&n,&m);
    176         int num1=0,num2=0;
    177         long long sum1=0,sum2=0;
    178         long long max_v=0;
    179         for (int a=1;a<=n;a++)
    180             for (int b=1;b<=m;b++)
    181             {
    182                 scanf("%lld",&map[a][b]);
    183                 if ((a+b)%2==0)
    184                 {
    185                     num1++;
    186                     sum1+=map[a][b];
    187                 }
    188                 else
    189                 {
    190                     num2++;
    191                     sum2+=map[a][b];
    192                 }
    193                 max_v=max(max_v,map[a][b]);
    194             }
    195         if (num1!=num2)
    196         {
    197             if ((sum1-sum2) % (num1-num2)!=0)
    198             {
    199                 printf("-1\n");
    200                 continue;
    201             }
    202             else
    203             {
    204                 long long x=(sum1-sum2)/(num1-num2);
    205                 if (x<max_v)
    206                 {
    207                     printf("-1\n");
    208                     continue;
    209                 }
    210                 if (check(x)) printf("%lld\n",gettime(x));
    211                 else printf("-1\n");
    212             }
    213         }
    214         else
    215         {
    216             long long l=max_v-1,r=INF;
    217             while (l+1!=r)
    218             {
    219                 long long m=(l+r)>>1;
    220                 if (check(m)) r=m;
    221                 else l=m;
    222             }
    223             if (check(r)) printf("%lld\n",gettime(r));
    224             else printf("-1\n");
    225         }
    226     }
    227  
    228     return 0;
    229 }

     

     

     

     

  • 相关阅读:
    linux 软件多版本共存
    git new
    centos 7 重新设置分区大小
    yum 多线程插件,apt多线程插件
    配置opencv cmake
    cmake 配置
    OpenCV 静态库 CMAKE 文件
    cron
    开课啦
    pytorch转onnx问题
  • 原文地址:https://www.cnblogs.com/zhonghaoxi/p/2476909.html
Copyright © 2020-2023  润新知