2756: [SCOI2012]奇怪的游戏

来源:互联网 发布:gv直播软件 编辑:程序博客网 时间:2024/05/16 02:24

2756: [SCOI2012]奇怪的游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 3052  Solved: 840
[Submit][Status][Discuss]

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 

 

Source

[Submit][Status][Discuss]



如果这个矩形一共有偶数个格子,那么显然可以二分答案

因为你总能找到一些方法把每个格子的数字累加上去

判断的话很容易想到用网络流

先把这个矩形二分图染色

记当前二分now为每个格子最后的状态

源点到每个黑点连容量为now - w[i][j]的边

每个白点到汇点连容量为now - w[i][j]的边

黑点与白点之间再连边模拟增加操作

跑一遍最大流


但是奇数的话就没办法二分了

列出几个等式

不妨假设最后每个格子的元素都是k

记初始时黑点权值和为sx,白点为sy,设黑点tx个,白点ty个

假设一共做了tot次增加操作

由于每个增加操作一定是一个黑点+1并且一个白点+1,那么

sx*tx + tot = k*tx

sy*ty + tot = k*ty

联立这两个式子消去tot,发现k的值唯一确定

再判断一下就好

#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<bitset>#include<algorithm>#include<cstring>#include<map>#include<stack>#include<set>#include<cmath>#include<ext/pb_ds/priority_queue.hpp>using namespace std;const int maxn = 1E5 + 10;typedef long long LL;const LL INF = 1E15;const int dx[4] = {1,0,-1,0};const int dy[4] = {0,1,0,-1};struct E{int to;LL cap,flow;E(){}E(int to,LL cap,LL flow): to(to),cap(cap),flow(flow) {}}edgs[maxn];int T,tot,cnt,s,t,n,m,Max,Cnt,A[55][55],co[55][55],vis[maxn],w[55][55],L[maxn],cur[maxn];LL goal,sum[2],p[2];vector <int> v[maxn];queue <int> Q;void Color(){s = Max = tot = 0;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {scanf("%d",&w[i][j]);A[i][j] = ++tot;Max = max(Max,w[i][j]);}t = ++tot;sum[0] = w[1][1]; p[0] = 1;sum[1] = p[1] = 0;co[1][1] = 0;for (int i = 2; i <= m; i++) {co[1][i] = co[1][i-1]^1;sum[co[1][i]] += 1LL*w[1][i];++p[co[1][i]];}for (int i = 2; i <= n; i++) {co[i][1] = co[i-1][1]^1;sum[co[i][1]] += 1LL*w[i][1];++p[co[i][1]];}for (int i = 2; i <= n; i++)for (int j = 2; j <= m; j++) {co[i][j] = co[i][j-1]^1;sum[co[i][j]] += 1LL*w[i][j];++p[co[i][j]];}}void Add(int x,int y,LL cap){v[x].push_back(cnt);edgs[cnt++] = E(y,cap,0);v[y].push_back(cnt);edgs[cnt++] = E(x,0,0);}bool BFS(){L[s] = 1;vis[s] = ++Cnt;Q.push(s);while (!Q.empty()) {int k = Q.front(); Q.pop();for (int i = 0; i < v[k].size(); i++) {E e = edgs[v[k][i]];if (e.cap == e.flow) continue;if (vis[e.to] == Cnt) continue;vis[e.to] = Cnt;L[e.to] = L[k] + 1;Q.push(e.to);}}return vis[t] == Cnt;}LL Dicnic(int x,LL a){if (x == t) return a;LL flow = 0;for (int &i = cur[x]; i < v[x].size(); i++) {E &e = edgs[v[x][i]];if (e.cap == e.flow) continue;if (L[e.to] != L[x] + 1) continue;LL f = Dicnic(e.to,min(a,e.cap - e.flow));if (!f) continue;e.flow += f;edgs[v[x][i]^1].flow -= f;flow += f;a -= f;if (!a) return flow;}if (!flow) L[x] = -1;return flow;}void Clear(){cnt = 0;for (int i = s; i <= t; i++) v[i].clear();}void Build(LL Now,LL &g0,LL &g1){for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {LL cap = Now - 1LL*w[i][j];if (!co[i][j]) {Add(s,A[i][j],cap);for (int k = 0; k < 4; k++) {int xx = i + dx[k];int yy = j + dy[k];if (xx < 1 || xx > n || yy < 1 || yy > m) continue;Add(A[i][j],A[xx][yy],INF);}g0 += cap;}else Add(A[i][j],t,cap),g1 += cap;}  }bool Judge(LL Now){LL g0,g1;g0 = g1 = 0;Build(Now,g0,g1);if (g0 != g1) {Clear();return 0;}LL MaxFlow = 0;while (BFS()) {for (int i = s; i <= t; i++) cur[i] = 0;MaxFlow += Dicnic(s,INF);}Clear();goal = g1;return g1 == MaxFlow;}void Solve1(){LL l = Max,r = INF;while (r - l > 1) {LL mid = (l + r) >> 1LL;if (Judge(mid)) r = mid;else l = mid;}if (Judge(l)) printf("%lld\n",goal);else if (Judge(r)) printf("%lld\n",goal);else puts("-1");}void Solve2(){LL Now = (sum[0] - sum[1]) / (p[0] - p[1]);if (Now < Max) puts("-1");else {if (Judge(Now)) printf("%lld\n",goal);else puts("-1");}}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);#endifcin >> T;while (T--) {scanf("%d%d",&n,&m);Color();if (n*m % 2 == 0) Solve1();else Solve2();}return 0;}

0 0