思路:
首先网络流在网格上经常用到黑白染色。其次如果涉及到一些平衡(相等之类)经常可以列流量平衡方程方程求解。
hzwer有很好的题解。这里只是贴代码。
/**************************************************************
Problem: 2756
User: DtenSherlock
Language: C++
Result: Accepted
Time:12568 ms
Memory:2888 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
typedef long long LL;
const int imax=40+9;
const int dmax=2290;
const int bmax=100000+229;
const LL inf=1LL<<61;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
int TT,n,m,id[imax][imax],tot; LL a[imax][imax];
int S,T,num,head[dmax],to[bmax],inext[bmax]; LL re[bmax];
void iread()
{
scanf("%d%d",&n,&m);
tot=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&a[i][j]),id[i][j]=++tot;
}
int d[dmax];
queue<int>q;
bool BFS()
{
memset(d,0,sizeof(d));
q.push(S); d[S]=1;
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=head[u];i!=-1;i=inext[i])
if(re[i] && !d[to[i]])
{
d[to[i]]=d[u]+1;
q.push(to[i]);
}
}
return d[T]>0;
}
LL DFS(int x,LL c)
{
if(x==T || c==0) return c;
LL r=c;
for(int i=head[x];i!=-1;i=inext[i])
if(d[to[i]]==d[x]+1)
{
LL f=DFS(to[i],min(re[i],r));
r-=f; re[i]-=f; re[i^1]+=f;
if(!r) break;
}
if(r==c) d[x]=0;
return c-r;
}
void iadd(int u,int v,LL flow){ to[num]=v; re[num]=flow; inext[num]=head[u]; head[u]=num++;}
void add(int u,int v,LL flow) { iadd(u,v,flow); iadd(v,u,0);}
bool pd(LL delta)
{
S=0; T=n*m+1;
for(int i=S;i<=T;i++) head[i]=-1;
num=0; LL sum=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if((i+j)&1) add(S,id[i][j],delta-a[i][j]),sum+=delta-a[i][j];
else add(id[i][j],T,delta-a[i][j]);
if(!((i+j)&1)) continue;
for(int k=0;k<4;k++)
{
int nowx=i+dx[k];
int nowy=j+dy[k];
if(nowx<1 || nowx>n || nowy<1 || nowy>m) continue;
add(id[i][j],id[nowx][nowy],inf);
}
}
LL nowans=0;
while(BFS()) nowans+=DFS(S,inf);
return (nowans==sum);
}
void iwork()
{
LL sum1=0; LL sum2=0; LL Max=0; int num1=0; int num2=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if((i+j)&1) num1++,sum1+=a[i][j];
else num2++,sum2+=a[i][j];
Max=max(Max,a[i][j]);
}
if(num1!=num2)
{
LL x=(sum1-sum2)/(num1-num2);
if(x>=Max)
{
if(pd(x))
{
printf("%lld\n",(x*num1-sum1));
return;
}
}
puts("-1");
}
else
{
LL l=Max; LL r=inf;
while(l<=r)
{
// printf("%lld %lld\n",l,r);
if(l+1==r || l==r)
{
if(pd(l)) r=l;
break;
}
LL Mid=(l+r)>>1;
if(pd(Mid)) r=Mid;
else l=Mid+1;
}
if(pd(r)) { printf("%lld\n",r*num1-sum1); return;}
puts("-1");
}
}
int main()
{
scanf("%d",&TT);
while(TT--)
{
iread();
iwork();
}
return 0;
}