zoukankan      html  css  js  c++  java
  • BZOJ 2756 SCOI2012 奇怪的游戏 最大流

    题目链接:http://www.lydsy.com/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

    ——————————————————————————————————————————————————

    题意概述:
    给出一个N*M的棋盘,每个格子有一个数,每次可以选择两个相邻的格子都+1。
    问最少操作多少次可以让所有的数变得一样,如果无解输出-1。

    分析:
    发现只知道操作次数并没有什么用(因为你也不知道要怎么去填)。
    假设最后的格子里的数是x。
    每次操作对相邻的两个格子进行,发现可以把棋盘上的格子分开来,黑白染色。

    抽象化表达:
    假设有c1个白色格子,c2个黑色格子,一开始白色格子的和为s1,黑色格子的和为s2,那么假如答案可以成立,由分别对于黑白格子操作次数相同,有:
    c1*x-s1=c2*x-s2 -> (c1-c2)*x=s1-s2

    可以发现当c1=c2的时候x的值并不是唯一确定的,但是根据黑白染色的分析,可以发现这种情况下棋盘长宽中至少有一个是偶数,黑白可以两两配对,满足二分性质。
    问题转化为判定。
    建立源点S,汇点T,S向所有的白格子连边,容量为需要提升的值,黑格子向T连边,容量也为需要提升的值。
    白点向周围的黑点连边,意义为这两个点一起提升的值,容量为inf。跑最大流看是否满流即可。

    c1-c2!=0 -> x=(s1-s2)/(c1-c2),那么可以直接判定:是否大于等于最大格子,是否可以整除,是否可以判定成功。

    小结:性质分析不出来怎么办?抽象成数学表达式再分析aaaaaaa!!!!

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<set>
      8 #include<map>
      9 #include<vector>
     10 #include<cctype>
     11 #define inf (1e12+5)
     12 using namespace std;
     13 const int MAXN=45;
     14 typedef long long LL;
     15 
     16 int T,N,M,A[MAXN][MAXN];
     17 int c1,c2,MAX; LL s1,s2;
     18 struct NET{
     19     static const int maxn=1605;
     20     static const int maxm=10005;
     21     struct edge{ int from,to,next; LL cap,flow; }E[maxm];
     22     int n,S,T,first[maxn],np,d[maxn],gap[maxn],fl[maxn],cur[maxn];
     23     NET(){ np=0; }
     24     void add_edge(int u,int v,LL c){
     25         E[++np]=(edge){u,v,first[u],c,0};
     26         first[u]=np;
     27         E[++np]=(edge){v,u,first[v],0,0};
     28         first[v]=np;
     29     }
     30     int id(int x,int y){ return (x-1)*M+y; }
     31     void init(LL m){
     32         memset(first,0,sizeof(first));
     33         np=0,n=N*M+2,S=n-1,T=n;
     34         LL re=0;
     35         for(int i=1;i<=N;i++)
     36         for(int j=1;j<=M;j++){
     37             if((i&1)&&(j&1)||!(i&1)&&!(j&1)){
     38                 add_edge(S,id(i,j),m-A[i][j]);
     39                 if(i-1) add_edge(id(i,j),id(i-1,j),inf);
     40                 if(j-1) add_edge(id(i,j),id(i,j-1),inf);
     41                 if(i+1<=N) add_edge(id(i,j),id(i+1,j),inf);
     42                 if(j+1<=M) add_edge(id(i,j),id(i,j+1),inf);
     43             }
     44             else add_edge(id(i,j),T,m-A[i][j]);
     45         }
     46     }
     47     void BFS(){
     48         queue<int>q;
     49         for(int i=1;i<=n;i++) d[i]=n;
     50         d[T]=0; q.push(T);
     51         while(!q.empty()){
     52             int i=q.front(); q.pop();
     53             for(int p=first[i];p;p=E[p].next){
     54                 int j=E[p].to,pp=(p-1^1)+1;
     55                 if(d[j]==n&&E[pp].cap>E[pp].flow) d[j]=d[i]+1,q.push(j);
     56             }
     57         }
     58     }
     59     LL augment(){
     60         LL flow=inf; int now=T;
     61         while(now!=S){
     62             flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
     63             now=E[fl[now]].from;
     64         }
     65         now=T;
     66         while(now!=S){
     67             E[fl[now]].flow+=flow,E[(fl[now]-1^1)+1].flow-=flow;
     68             now=E[fl[now]].from;
     69         }
     70         return flow;
     71     }
     72     bool ISAP(){
     73         memcpy(cur,first,sizeof(first));
     74         memset(gap,0,sizeof(gap));
     75         BFS();
     76         for(int i=1;i<=n;i++) gap[d[i]]++;
     77         int now=S; LL flow=0;
     78         while(d[S]<n){
     79             if(now==T) flow+=augment(),now=S;
     80             bool ok=0;
     81             for(int p=cur[now];p;p=E[p].next){
     82                 int j=E[p].to;
     83                 if(E[p].cap>E[p].flow&&d[j]+1==d[now]){
     84                     ok=1,cur[now]=fl[j]=p,now=j;
     85                     break;
     86                 }
     87             }
     88             if(!ok){
     89                 int minl=n;
     90                 for(int p=first[now];p;p=E[p].next){
     91                     int j=E[p].to;
     92                     if(E[p].cap>E[p].flow&&d[j]+1<minl) minl=d[j]+1;
     93                 }
     94                 if(--gap[d[now]]==0) break;
     95                 gap[d[now]=minl]++;
     96                 cur[now]=first[now];
     97                 if(now!=S) now=E[fl[now]].from;
     98             }
     99         }
    100         for(int p=first[S];p;p=E[p].next)
    101             if(E[p].cap!=E[p].flow) return 0;
    102         for(int p=first[T],pp=(p-1^1)+1;p;p=E[p].next,pp=(p-1^1)+1)
    103             if(E[pp].cap!=E[pp].flow) return 0;
    104         return 1;
    105     }
    106 }net;
    107 
    108 void data_in()
    109 {
    110     scanf("%d%d",&N,&M);
    111     for(int i=1;i<=N;i++)
    112     for(int j=1;j<=M;j++)
    113         scanf("%d",&A[i][j]);
    114     c1=c2=MAX=0,s1=s2=0;
    115     for(int i=1;i<=N;i++)
    116     for(int j=1;j<=M;j++){
    117         if((i&1)&&(j&1)||!(i&1)&&!(j&1)) s1+=A[i][j],c1++;
    118         else s2+=A[i][j],c2++;
    119         MAX=max(MAX,A[i][j]);
    120     }
    121 }
    122 bool check(LL mid)
    123 {
    124     net.init(mid);
    125     return net.ISAP();
    126 }
    127 void work()
    128 {
    129     if(c1==c2){
    130         LL L=MAX,R=inf,mid,ans=-1;
    131         while(L<R){
    132             mid=L+R>>1;
    133             if(check(mid)) R=mid,ans=mid;
    134             else L=mid+1;
    135         }
    136         if(ans!=-1) cout<<(ans*N*M-s1-s2)/2<<'
    ';
    137         else cout<<ans<<'
    ';
    138     }
    139     else{
    140         if((s1-s2)%(c1-c2)==0&&(s1-s2)/(c1-c2)>=MAX){
    141             LL ans=(s1-s2)/(c1-c2);
    142             if(check(ans)) cout<<(ans*N*M-s1-s2)/2<<'
    ';
    143             else cout<<-1<<'
    ';
    144         }
    145         else cout<<-1<<'
    ';
    146     }
    147 }
    148 int main()
    149 {
    150     scanf("%d",&T);
    151     while(T--){
    152         data_in();
    153         work();
    154     }
    155     return 0;
    156 }
  • 相关阅读:
    Annotation
    GIT的作用以及Versioncontrol为什么要用GIT
    Http协议
    人工智能的可怕与不可怕
    Makefile简易教程
    Node.js 学习笔记之一:学习规划 & 认知 Node.js
    《大教堂与集市》的启示 — 软件工程的另一种选择
    Git简易教程
    谈谈买书与读书
    clang编译器简介
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8597724.html
Copyright © 2011-2022 走看看