2756: [SCOI2012]奇怪的游戏

Time Limit: 40 Sec  Memory Limit: 128 MB

Description

Blinke 最近喜欢上一个奇怪的游戏。 这个游戏在一个 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

题解

首先,我们可以很明显的看出最后形成的数\(x\)一定具有单调性,所以我们可以二分\(x\)。

那么如何写\(check(x)\)呢?

首先我们可以将棋盘黑白染色,之后再将黑色与\(T\)相连,将白色与\(S\)相连,再将黑白色之间连接。这样就可以用一个最大流来解决。

因为每个数字都要变为\(x\),所以可以将节点与\(S\)或\(T\)相连的边权设为\(x-val\),之后我们可以将黑白棋子之间的边权设为\(inf\)(其实边权值可以算出,不过由于之前已经限制了边权,所以这里可以不用处理边权)。

因为这个最大流其实就是加了多少次,所以最大流应该等于所有数字与x之差之和的一半。这样,我们就可以写出\(check\)了。

另外,因为\(Cnt[0]*x - Sum[0]=Cnt[1]*x - Sum[1]\),\(Cnt\)表示黑白棋格的个数,\(Sum\)表示黑白棋格各自的和,所以当\(Cnt[0] \neq Cnt[1]\)时,我们可以直接得出\(x\),之后直接\(check(x)\)就好了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
const int MS = 100000, N = 42;
const LL inl = 1LL << 55; int ina; char inc, inb[1<<16], *ins = inb, *ine = inb; bool insign;
inline char getc() {
if (ins == ine) ine = (ins = inb) + fread(inb, 1, 1 << 16, stdin);
return (ins == ine) ? EOF : *ins++;
}
inline int geti() {
insign = false;
while ((inc = getc()) < '0' || inc > '9') insign |= inc == '-'; ina = inc - '0';
while ((inc = getc()) >= '0' && inc <= '9') ina = (ina << 3) + (ina << 1) + inc - '0';
return insign ? -ina : ina;
} int mp[N][N], n, m;
bool col[N][N];
LL Sum[2], Num[2], mv; namespace CC {
int To[MS], Nxt[MS], totE, head[N * N], S, T, d[N * N], dt[N * N];
LL C[MS];
inline void Adde(int a, int b, LL c) {
To[totE] = b; Nxt[totE] = head[a]; C[totE] = c; head[a] = totE++;
To[totE] = a; Nxt[totE] = head[b]; C[totE] = 0; head[b] = totE++;
} const int dx[] = {0,0,-1,1};
const int dy[] = {1,-1,0,0}; inline int getp(const int &x, const int &y) { return (x-1)*m + y; } LL dfs(int u, LL flow) {
if (u==T||!flow) return flow;
LL res = 0, t;
for (int i = head[u]; ~i; i = Nxt[i])
if (d[u] == d[To[i]] + 1 && C[i] > 0){
t = dfs(To[i], min(flow, C[i]));
C[i] -= t, C[i^1] += t;
res += t, flow -= t;
if (!flow) return res;
if (d[S] > T) return res;
}
if (!(--dt[d[u]])) d[S] = T + 1;
++dt[++d[u]];
return res;
} bool check(LL x) {
memset(head, -1, sizeof head); totE = 0;
S = 0, T = getp(n, m) + 1;
LL t, tot = 0, maxflow = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
t = x - mp[i][j];
if (col[i][j]) Adde(getp(i, j), T, t);
else Adde(S, getp(i, j), t);
tot += t;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
for (int k = 0; k < 4; ++k) {
int _i = i + dx[k], _j = j + dy[k];
if (_i < 1 || _i > n || _j < 1 || _j > m) continue;
if (!col[i][j]) Adde(getp(i, j), getp(_i, _j), inl);
}
memset(d, 0, sizeof d); memset(dt, 0, sizeof dt);
dt[0] = T + 1;
while (d[S] < T + 1) maxflow += dfs(S, inl);
return tot == (maxflow << 1);
} }
void init() {
memset(col, 0, sizeof col);
n = geti(), m = geti();
*Sum = Sum[1] = *Num = Num[1] = mv = 0LL;
bool st = true;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
if ((mp[i][j] = geti()) > mv) mv = mp[i][j];
col[i][j] = !col[i][j-1];
if (j <= 1) col[i][j] = (st = !st);
++Num[col[i][j]]; Sum[col[i][j]] += mp[i][j];
}
} #define getskip(a) (a*n*m - Sum[0] - Sum[1]) >> 1 void Work() {
if (n * m & 1) {
LL x = Sum[0] - Sum[1];
if (x >= mv && CC::check(x)) printf("%lld\n", getskip(x));
else puts("-1");
} else {
LL l = mv, r = inl / 1000, M, ans = -1;
while (l <= r) {
M = l + r >> 1;
if (CC::check(M)) r = (ans = M) - 1;
else l = M + 1;
}
if (~ans) printf("%lld\n", getskip(ans));
else puts("-1");
}
} int main() {
for (int T = geti(); T; --T) {
init(); Work();
}
return 0;
}

bzoj 2756奇怪的游戏的更多相关文章

  1. [BZOJ 2756] 奇怪的游戏

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2756 Algorithm: 比较新颖的题目 首先发现是对矩阵中相邻两数进行操作    & ...

  2. BZOJ 2756 奇怪的游戏(最大流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2756 题意:在一个 N*M 的棋盘上玩,每个格子有一个数.每次 选择两个相邻的格子,并使 ...

  3. 【BZOJ】【2756】【SCOI2012】奇怪的游戏

    网络流-最大流 这题……建模部分先略过 这道题是会卡时限的T_T俺的Dinic被卡了,在此放几篇很棒的讲网络流算法的文章,至于大家耳熟能详的论文就不放了…… http://www.cppblog.co ...

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

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

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

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

  6. BZOJ 2756 SCOI2012 奇怪的游戏 最大流

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...

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

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

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

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

  9. BZOJ 2756 【SCOI2012】 奇怪的游戏

    题目链接:奇怪的游戏 一开始这道题想岔了……想到黑白染色后对总格子数按奇偶性分类讨论,然后没发现奇数个格子的可以直接解方程…… 首先可以发现每次操作是给相邻的两个格子权值加一,因此我们把棋盘黑白染色后 ...

随机推荐

  1. [windows]win10家庭版切换到管理员账户

    背景:很多时候,在安装或者运行某些程序时会需要到管理员账户运行.而在win10家庭版却没有明显的位置可以让用户简单的进行切换.因此,有了以下的方法. 方法: 1.在搜索框中输入CMD,右键以管理员方式 ...

  2. RMAN-06023: no backup or copy of datafile 1 found to restore

    在ORACLE 10g数据库还原过程遭遇RMAN-06023: no backup or copy of datafile x found to restore,具体情况如下所示 .......... ...

  3. ORA-01502: index ‘index_name' or partition of such index is in unusable state

    错误现象: 今天发布脚本时,一个表插入数据时报如下错误 ORA-01502: index ‘index_name' or partition of such index is in unusable ...

  4. SQLite学习笔记(七)&&事务处理

    说到事务一定会提到ACID,所谓事务的原子性,一致性,隔离性和持久性.对于一个数据库而言,通常通过并发控制和故障恢复手段来保证事务在正常和异常情况下的ACID特性.sqlite也不例外,虽然简单,依然 ...

  5. Writing to a MySQL database from SSIS

    Writing to a MySQL database from SSIS 出处  :  http://blogs.msdn.com/b/mattm/archive/2009/01/07/writin ...

  6. [Java入门笔记] Java语言基础(一):注释、标识符与关键字

    注释 什么是注释? 注释是我们在编写代码时某段代码.某个方法.某个类的说明文字,方便大家对于代码的阅读.被注释的内容不会被编译.执行. Java的注释分为三种类型:单行注释.多行注释.文档注释. 单行 ...

  7. Live Migrate 操作 - 每天5分钟玩转 OpenStack(42)

    Migrate 操作会先将 instance 停掉,也就是所谓的“冷迁移”.而 Live Migrate 是“热迁移”,也叫“在线迁移”,instance不会停机. Live Migrate 分两种: ...

  8. audacity开源VS2013环境搭建

    audacity是非常不错的音频开源,其中音频效果处理的种类很多,非常方便借鉴和研究. 但是audacity的界面库是使用wxWidgets(一个跨平台的界面库),配置过程中需要折腾一下. 1,首先去 ...

  9. [WPF系列]-数据邦定之DataTemplate 对分层数据的支持

    到目前为止,我们仅讨论如何绑定和显示单个集合. 某些时候,您要绑定的集合包含其他集合. HierarchicalDataTemplate 类专用于 HeaderedItemsControl 类型以显示 ...

  10. 解决:PADS导入.DXF结构图出现坐标超出范围问题

    现象: 原因: PCB尺寸是有限的,PADS中对于坐标大小有所限制,但AUTO CAD中的坐标却是无限制的. 解决方法: 1.在AUTO中使用M命令,将绘制的结构图移动至原点: 2.在AUTO中使用W ...