题目

Blinker最近喜欢上一个奇怪的游戏。

这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻

的格子,并使这两个数都加上 1。

现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同

一个数则输出-1。

输入格式

输入的第一行是一个整数T,表示输入数据有T轮游戏组成。

每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。

接下来有N行,每行 M个数。

输出格式

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

输入样例

2

2 2

1 2

2 3

3 3

1 2 3

2 3 4

4 3 2

输出样例

2

-1

提示

【数据范围】

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

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

题解

我们将原图黑白染色就会发现每次一定是一黑一白+1

那么我们可以分类讨论:

记黑色n1个总和s1,白色n2个总和s2

①若n1 == n2

二者s1 != s2,无论如何也不会相等

二者s1 == s2,用网络流二分检验:

S向其中一种颜色建边,容量为还差的值

同时这种颜色向周围建边,容量INF

另一种颜色向T建边,容量为还差的值

看看是否满流

②若n1 != n2

我们设x为最后的值

由黑白增量相同,可以得到等式:

x∗n1−s1=x∗n2−s2

化简:

x=s1−s2n1−n2

可见x为定值,若x比最大的数小,无解

否则网络流判断一下

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 45,maxm = 1000005;
const LL INF = (1ll << 50);
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
LL s[maxn][maxn],N,M,n1,n2,mx;
LL s1,s2,d[maxn * maxn];
int X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0},c[maxn][maxn];
int h[maxn * maxn],ne,S,T,vis[maxn * maxn],cur[maxn * maxn];
struct EDGE{int to,nxt; LL f;}ed[maxm];
inline void build(int u,int v,LL w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++;
}
bool bfs(){
queue<int> q; int u;
for (int i = S; i <= T; i++) d[i] = INF,vis[i] = false;
d[S] = 0; vis[S] = true; q.push(S);
while (!q.empty()){
u = q.front(); q.pop();
Redge(u) if (ed[k].f && !vis[to = ed[k].to]){
d[to] = d[u] + 1; vis[to] = true; q.push(to);
}
}
return vis[T];
}
LL dfs(int u,LL minf){
if (u == T || !minf) return minf;
LL f,flow = 0; int to;
if (cur[u] == -1) cur[u] = h[u];
for (int& k = cur[u]; k; k = ed[k].nxt)
if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
ed[k].f -= f; ed[k ^ 1].f += f;
flow += f; minf -= f;
if (!minf) break;
}
return flow;
}
LL maxflow(){
LL flow = 0;
while (bfs()){fill(cur,cur + maxn * maxn,-1); flow += dfs(S,INF);}
return flow;
}
bool check(LL x){
S = 0; T = N * M + 1; ne = 2; memset(h,0,sizeof(h));
LL tot = 0;
REP(i,N) REP(j,M){
if (c[i][j]){
build(S,(i - 1) * M + j,x - s[i][j]),tot += x - s[i][j];
for (int k = 0; k < 4; k++){
int nx = i + X[k],ny = j + Y[k];
if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
build((i - 1) * M + j,(nx - 1) * M + ny,INF);
}
}else build((i - 1) * M + j,T,x - s[i][j]);
}
return tot == maxflow();
}
void solve1(){
LL x = (s1 - s2) / (n1 - n2);
if (x < mx || !check(x)) puts("-1");
else printf("%lld\n",x * n1 - s1);
}
void solve2(){
if (s1 != s2) {puts("-1"); return;}
LL L = mx,R = INF,mid;
while (L <= R){
mid = L + R >> 1;
if (check(mid)) R = mid - 1;
else L = mid + 1;
}
printf("%lld\n",(LL)L * n1 - s1);
}
int main(){
int Tim = read();
while (Tim--){
N = read(); M = read(); n1 = n2 = s1 = s2 = 0; mx = 0;
REP(i,N) REP(j,M) c[i][j] = (i + j ) & 1,s[i][j] = read();
REP(i,N) REP(j,M){
if (c[i][j]) n1++,s1 += s[i][j];
else n2++,s2 += s[i][j];
mx = max(mx,s[i][j]);
}
if (n1 != n2) solve1();
else solve2();
}
return 0;
}

BZOJ2756 [SCOI2012]奇怪的游戏 【网络流 + 二分】的更多相关文章

  1. bzoj2756: [SCOI2012]奇怪的游戏(网络流+分情况)

    2756: [SCOI2012]奇怪的游戏 题目:传送门 题解: 发现做不出来的大难题一点一个网络流 %大佬 首先黑白染色(原来是套路...)染色之后就可以保证每次操作都一定会使黑白各一个各自的值加1 ...

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

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

  3. BZOJ2756 SCOI2012奇怪的游戏(二分答案+最大流)

    由数据范围容易想到网络流.由于操作只是对于棋盘上相邻两格,容易想到给其黑白染色. 假设已经知道最后要变成什么数.那么给黑白点之间连边,其流量则表示同时增加的次数,再用源汇给其限流为需要增加的数即可. ...

  4. 【BZOJ2756】奇怪的游戏(二分,网络流)

    [BZOJ2756]奇怪的游戏(二分,网络流) 题面 BZOJ Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blink ...

  5. Bzoj2756 [SCOI2012]奇怪的游戏

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3220  Solved: 886 Description ...

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

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

  7. 【BZOJ2756】奇怪的游戏(二分,最小割)

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

  8. 洛谷5038 [SCOI2012]奇怪的游戏(二分+网络流+判断奇偶)

    寒假的时候就听过这个题.但是一直没有写. qwq 首先,我们发现题目中的图是个网格图,然后每次可以将相邻两个格子加一. 很容易就想到是黑白染色.那么每次操作,就相当于同时操作一个白点,一个黑点. 我们 ...

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

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

随机推荐

  1. Linux相关知识

    1.设置代理 sudo vi /etc/apt/apt.conf Acquire::http::Proxy "http://proxy_address:8080/"; 2.生成 s ...

  2. springMVC-数据绑定

    定义: 将http请求中参数绑定到Handler业务方法 常用数据绑定类型 1.  基本数据类型 不能为其它类型和null值 2.  包装类 可以为其它对象,全部转成null值 3.  数组 多个对象 ...

  3. glibc2.12升级至2.15

    1.操作系统版本 [root@localhost ~]# cat /etc/redhat-release #CentOS release 6.9 (Final) 2.当前glibc版本 [root@l ...

  4. DB - RDMS - MySQL优化

    慢SQL会消耗打来难过的数据库CPU资源,特别是频繁执行的慢SQL语句,会造成大量任务的堆积,CPU瞬间增大.

  5. linux学习笔记二:三种网络配置

    本文引用自:https://www.linuxidc.com/Linux/2017-05/144370.htm [linux公社] VMware为我们提供了三种网络工作模式,它们分别是:Bridged ...

  6. JAVA / MySql 编程——第五章 事务、视图、索引、备份和恢复

    1.事务(Transaction): 事务是将一系列数据操作绑成一个整体进行统一管理. 如果一事务执行成功,则咋子该事务中进行的所有数据更改均会提交,称为数据库中的永久成部分. 如果事务执行是遇到错误 ...

  7. redis源代码结构解析

    看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识: 之前面试的时候被问到了这部分的内容,没有关注,好在还有时间,就把Redis的源码看了一遍. Redis ...

  8. composer环境安装

    PHP很多优秀的框架,例如Laravel等等,镜像都在国外,相关的包管理工具Composer也是在国外,所以安装失败的可能性很大,题主所示的就是因为连不上Composer.解决方法如下: 进入官网, ...

  9. 微信小程序禁止下拉_解决小程序下拉出现空白的情况

    微信小程序禁止下拉 在微信小程序中,用力往下拉动,页面顶部会出现一段空白的地方. 产品的需求不太允许这么做,会影响用户体验,查看文档发现可以使用enablePullDownRefresh这属性来实现, ...

  10. sparkStreaming统计各平台最近一分钟实时注册收入 时间段,平台,金额,订单数

    样例数据: __clientip=10.10.9.153&paymentstatus=0&__opip=&memberid=89385239&iamount=1& ...