一个有很多细节要注意的题。。。。。交到第15发终于过了。。。。。
所有的数据都要到用longlong 然后要判断最高的棍子
将棋盘黑白染色,源向黑(1)连 1向四周0连 0向汇连
如果n*m是偶数 那么黑位置的值之和要等于白格子的值之和(因为每加一个板子,黑白的值都加一)
如果n*m是基数 那么黑棋子或白棋子多一个 d就是(sum1-sum0)/(num1-num0);
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
typedef long long sint;
#define maxn 10000
#define INF (1ll<<33)
struct node
{
int u,v;
sint f;
}e[maxn];
int st,ed,en,first[maxn],next[maxn],cur[maxn];;
sint ans,dis[maxn],save[200][200];
int num,num0,num1,m,n,lab[200][200],lab2[100][100];
sint sum0,sum1,maxflow,lim;
int dx[]={0,1,0,0,-1};
int dy[]={0,0,1,-1,0};
sint getint()
{
sint res,f=1;char c;
while(c=getchar(),c<'0'||c>'9')
if(c=='-') f=-1;
res=c-'0';
while(c=getchar(),c>='0'&&c<='9')
res=res*10+c-'0';
return res*f;
}
void init()
{
memset(first,-1,sizeof(first));
en=-1;
}
void add(int a,int b,sint c)
{
en++;
e[en].v=b;
e[en].f=c;
next[en]=first[a];
first[a]=en;
en++;
e[en].v=a;
e[en].f=0;
next[en]=first[b];
first[b]=en;
}
bool bfs()
{
queue<int>q;
memset(dis,-1,sizeof(dis));
q.push(st);
dis[st]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=first[u];i!=-1;i=next[i])
{
int v=e[i].v;
if(dis[v]!=-1||e[i].f==0) continue;
dis[v]=dis[u]+1;
if(v==ed)
{
return true;
}
q.push(v);
}
}
return false;
}
sint dfs(int x,sint mx)
{
if(mx==0||x==ed) return mx;
sint tmp,flow=0,res=0;
for(int& i=cur[x];i!=-1;i=next[i])
{
int v=e[i].v;
if(e[i].f==0) continue;
if(dis[v]!=dis[x]+1) continue;
tmp=dfs(v,min(mx,e[i].f));
flow+=tmp;
e[i].f-=tmp;
e[i^1].f+=tmp;
mx-=tmp;
if(!mx) break;
}
if(!flow) dis[x]=-1;
return flow;
}
sint dinic()
{
sint tmp=0;
maxflow=0;
while(bfs())
{
for(int i=1;i<=ed;i++) cur[i]=first[i];
while(tmp=dfs(st,INF)) maxflow+=tmp;
}
return maxflow;
}
sint getflow(sint x)
{
int xx,yy;
init();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(lab2[i][j]==1)
{
add(st,lab[i][j],x-save[i][j]);
for(int k=1;k<=4;k++)
{
xx=dx[k]+i;
yy=dy[k]+j;
if(xx<1||xx>n||yy<1||yy>m) continue;
add(lab[i][j],lab[xx][yy],INF);
}
}
else
{
add(lab[i][j],ed,x-save[i][j]);
}
}
}
return dinic();
}
bool check(sint x)
{
init();
sint sum=x*n*m;
if(x<lim) return false;
if(getflow(x)*2==sum-sum0-sum1)
return true;
return false;
}
void solve0()
{
sint l=0,r=INF,mid,tmp;
if(sum1!=sum0)
{
printf("-1\n");
return;
}
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
{
ans=maxflow;
r=mid-1;
}
else
{
l=mid+1;
}
}
if(ans!=-1)
printf("%lld\n",ans);
else
printf("-1\n");
return;
}
void solve1()
{
sint d=(sum1-sum0)/(num1-num0);
if(check(d))
{
printf("%lld\n",maxflow);
}
else printf("-1\n");
}
int main()
{
//freopen("input.txt","r",stdin);
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
sum0=sum1=0;
num0=num1=num=0;
lim=-INF;
ans=-1;
st=m*n+1;
ed=m*n+2;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
save[i][j]=getint();
lim=max(lim,save[i][j]);
num++;
lab[i][j]=num;
lab2[i][j]=(i+j)&1;
if(lab2[i][j]==1)
{
sum1+=save[i][j];
num1++;
}
else
{
num0++;
sum0+=save[i][j];
}
}
}
if(n*m%2==0) solve0();
else solve1();
}
return 0;
}