题目链接: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!!!!

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
#define inf (1e12+5)
using namespace std;
const int MAXN=;
typedef long long LL; int T,N,M,A[MAXN][MAXN];
int c1,c2,MAX; LL s1,s2;
struct NET{
static const int maxn=;
static const int maxm=;
struct edge{ int from,to,next; LL cap,flow; }E[maxm];
int n,S,T,first[maxn],np,d[maxn],gap[maxn],fl[maxn],cur[maxn];
NET(){ np=; }
void add_edge(int u,int v,LL c){
E[++np]=(edge){u,v,first[u],c,};
first[u]=np;
E[++np]=(edge){v,u,first[v],,};
first[v]=np;
}
int id(int x,int y){ return (x-)*M+y; }
void init(LL m){
memset(first,,sizeof(first));
np=,n=N*M+,S=n-,T=n;
LL re=;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
if((i&)&&(j&)||!(i&)&&!(j&)){
add_edge(S,id(i,j),m-A[i][j]);
if(i-) add_edge(id(i,j),id(i-,j),inf);
if(j-) add_edge(id(i,j),id(i,j-),inf);
if(i+<=N) add_edge(id(i,j),id(i+,j),inf);
if(j+<=M) add_edge(id(i,j),id(i,j+),inf);
}
else add_edge(id(i,j),T,m-A[i][j]);
}
}
void BFS(){
queue<int>q;
for(int i=;i<=n;i++) d[i]=n;
d[T]=; q.push(T);
while(!q.empty()){
int i=q.front(); q.pop();
for(int p=first[i];p;p=E[p].next){
int j=E[p].to,pp=(p-^)+;
if(d[j]==n&&E[pp].cap>E[pp].flow) d[j]=d[i]+,q.push(j);
}
}
}
LL augment(){
LL flow=inf; int now=T;
while(now!=S){
flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
now=E[fl[now]].from;
}
now=T;
while(now!=S){
E[fl[now]].flow+=flow,E[(fl[now]-^)+].flow-=flow;
now=E[fl[now]].from;
}
return flow;
}
bool ISAP(){
memcpy(cur,first,sizeof(first));
memset(gap,,sizeof(gap));
BFS();
for(int i=;i<=n;i++) gap[d[i]]++;
int now=S; LL flow=;
while(d[S]<n){
if(now==T) flow+=augment(),now=S;
bool ok=;
for(int p=cur[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+==d[now]){
ok=,cur[now]=fl[j]=p,now=j;
break;
}
}
if(!ok){
int minl=n;
for(int p=first[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+<minl) minl=d[j]+;
}
if(--gap[d[now]]==) break;
gap[d[now]=minl]++;
cur[now]=first[now];
if(now!=S) now=E[fl[now]].from;
}
}
for(int p=first[S];p;p=E[p].next)
if(E[p].cap!=E[p].flow) return ;
for(int p=first[T],pp=(p-^)+;p;p=E[p].next,pp=(p-^)+)
if(E[pp].cap!=E[pp].flow) return ;
return ;
}
}net; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++)
for(int j=;j<=M;j++)
scanf("%d",&A[i][j]);
c1=c2=MAX=,s1=s2=;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
if((i&)&&(j&)||!(i&)&&!(j&)) s1+=A[i][j],c1++;
else s2+=A[i][j],c2++;
MAX=max(MAX,A[i][j]);
}
}
bool check(LL mid)
{
net.init(mid);
return net.ISAP();
}
void work()
{
if(c1==c2){
LL L=MAX,R=inf,mid,ans=-;
while(L<R){
mid=L+R>>;
if(check(mid)) R=mid,ans=mid;
else L=mid+;
}
if(ans!=-) cout<<(ans*N*M-s1-s2)/<<'\n';
else cout<<ans<<'\n';
}
else{
if((s1-s2)%(c1-c2)==&&(s1-s2)/(c1-c2)>=MAX){
LL ans=(s1-s2)/(c1-c2);
if(check(ans)) cout<<(ans*N*M-s1-s2)/<<'\n';
else cout<<-<<'\n';
}
else cout<<-<<'\n';
}
}
int main()
{
scanf("%d",&T);
while(T--){
data_in();
work();
}
return ;
}

BZOJ 2756 SCOI2012 奇怪的游戏 最大流的更多相关文章

  1. BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3352  Solved: 919[Submit][Stat ...

  2. BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1594  Solved: 396[Submit][Stat ...

  3. bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流

    2756:[SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 4926  Solved: 1362[Submit][Stat ...

  4. bzoj 2756: [SCOI2012]奇怪的游戏

    Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...

  5. BZOJ.2756.[SCOI2012]奇怪的游戏(二分 黑白染色 最大流ISAP)

    题目链接 \(Description\) \(Solution\) 这种题当然要黑白染色.. 两种颜色的格子数可能相同,也可能差1.记\(n1/n2\)为黑/白格子数,\(s1/s2\)为黑/白格子权 ...

  6. bzoj 2756 [SCOI2012]奇怪的游戏【二分+最大流】

    达成成就:为二分调参 !:多次memset的话要把数组大小开严格一点,否则会T 看到网格图,首先黑白染色. 注意到每次操作都是在一个黑格子和一个白格子上进行的,也就是说,最后黑格子数字和白格子数字和的 ...

  7. BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)

    Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...

  8. BZOJ2756 [SCOI2012]奇怪的游戏 最大流

    好久没有写博客了.不过这个博客也没有多少人看 最近在写网络流,为了加深理解,来写一两篇题解. 对整个棋盘进行黑白染色以后可以发现,一次操作就是让二分图的两个点的值分别 \(+1\). 这样,我们就可以 ...

  9. 【BZOJ-2756】奇怪的游戏 最大流 + 分类讨论 + 二分

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 2925  Solved: 792[Submit][Stat ...

随机推荐

  1. Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

    Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition Kaiming He, Xiangyu Zh ...

  2. redis的安装和启动linux环境

    启动客户端连接redis服务,redis-cli -p(端口) -h(登录的服务的ip地址);不添加任何参数和选项直接使用redis-cli将会默认登录6379,默认使用ip 127.0.0.1#re ...

  3. mysql 复制A表 到B表;insert into select * from table

    情况一: INSERT INTO tb1 (a,b,c) select a1,b1,c1, from tb2 where .... --  案例 百度云 INSERT INTO l_biz_car_o ...

  4. oracle https://localhost:1158/em 无法打开

    解决办法一: 首先查看本机Oracle安装路径中 portlist.ini 文件里面的端口号是多少,例如我的就是5500. 那么在浏览器中输入的地址就是:https://localhost:5500/ ...

  5. iOS 获取APP的CPU、内存等信息

    目标是开发一个SDK,嵌入到APP里面,用来统计当前APP的实时CPU.内存等信息 2015.11.17 http://stackoverflow.com/questions/12889422/ios ...

  6. ABAP术语-Business Scenario

    Business Scenario 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/12/1035980.html End-to-end co ...

  7. docker 启动 nginx 访问不了的问题

    使用版本:nginx version: nginx/1.13.8 正使用docker启动nginx容器的时候,一切都很正常,容器也起来了 docker run -dit -p 80:80 --name ...

  8. Docker(一):概述

    Docker 是什么? Docker是一个开源的应用容器引擎,基于Go语言开发 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后 ...

  9. CRC校验8

    什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并 ...

  10. Python函数中的参数

    形参:形式参数 实参:实际参数 1.普通参数:严格按照顺序将实参赋值给形参. 2.默认参数:必须放置在参数列表的最后. 3.指定参数:将实参赋值给制定参数. 4.动态参数: *:默认将传入的参数,全部 ...