题解:
将网格图图黑白染色转化为二分图,容易发现问题转化为求点权最大的独立集。
因为二分图中最大独立集和最小点覆盖是互补的关系,所以用最小割求最小点覆盖即可。
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=1e4+50,M=2e6+50,INF=0x3f3f3f3f;
int n,m,src,des;
int g[N],vt[M],nt[M],w[M],ec=1;
int lev[N],cur[N];
inline void add(int x,int y,int c) {
nt[++ec]=g[x]; g[x]=ec; vt[ec]=y; w[ec]=c;
nt[++ec]=g[y]; g[y]=ec; vt[ec]=x; w[ec]=0;
}
queue <int> q;
inline bool bfs() {
while(!q.empty()) q.pop();
memset(lev+1,0,sizeof(int)*des);
lev[src]=1; q.push(src);
while(!q.empty()) {
int u=q.front(); q.pop();
for(int e=g[u];e;e=nt[e]) {
if(!w[e] || lev[vt[e]]) continue;
lev[vt[e]]=lev[u]+1; q.push(vt[e]);
if(vt[e]==des) return true;
}
} return false;
}
inline int dinic(int x,int f) {
if(x==des) return f;
int rs=0;
for(int e=g[x];e;e=nt[e]) {
if(!w[e] || (lev[vt[e]]!=lev[x]+1)) continue;
int o=dinic(vt[e],min(w[e],f-rs));
w[e]-=o; w[e^1]+=o; rs+=o;
if(rs==f) return rs;
} return lev[x]=0,rs;
}
inline int maxflow() {
int rs=0;
while(bfs()) {
int t=0; memcpy(cur+1,g+1,sizeof(int)*des);
while((t=dinic(src,INF))) rs+=t,memcpy(cur+1,g+1,sizeof(int)*des);
} return rs;
}
const int fx[]={0,0,0,1,-1};
const int fy[]={0,1,-1,0,0};
inline int id(int x,int y) {return (x-1)*m+y;}
inline bool check(int x,int y) {return x>0&&x<=n&&y>0&&y<=m;}
int main() {
n=rd(),m=rd(); src=10001,des=10002;
int sum=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
int x=rd(); sum+=x;
if((i+j)&1) add(id(i,j),des,x);
else add(src,id(i,j),x);
for(int k=1;k<=4;k++) {
int xx=i+fx[k],yy=j+fy[k];
if((!((i+j)&1))&&check(xx,yy)) add(id(i,j),id(xx,yy),INF);
}
}
printf("%d\n",sum-maxflow());
}