题意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
难度:1
题解:最大点权独立集。与骑士共存问题相似,用最大流求解。对每个点进行黑白染色,使得每对相邻的点的颜色不同,新建一个附加源s和一个附加汇t,s对所有黑点连一条容量为改点权值的边,所有白点对t连一条容量为改点权值的边,所有黑点对其相邻的点连一条容量无穷大的边,所有点的权值和减去求得的最大流就是答案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf (1<<29)
#define forn(i,n) for(i=0;i<(n);i++)
#define for1(i,n) for(i=1;i<=(n);i++)
#define forh(i,u) for(i=head[u];i!=-1;i=edge[i].next)
const int maxn = 5005 , maxm = 2500005;
struct Edge {
int u,v,c,next;
}edge[maxm];
int E,head[maxn];
int dep[maxn];
int gap[maxn];
int n;
void init() {
E=0;memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c) {
edge[E].u=u;
edge[E].v=v;
edge[E].c=c;
edge[E].next=head[u];
head[u]=E++;
edge[E].u=v;
edge[E].v=u;
edge[E].c=0;
edge[E].next=head[v];
head[v]=E++;
}
void bfs(int scr,int des) {
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
gap[0]=-1;
int que[maxn];
int front,rear;
front=rear=0;
dep[des]=0;
que[rear++]=des;
while(front!=rear) {
int u=que[front++];
if(front==maxn) front=0;
for(int i=head[u];i!=-1;i=edge[i].next) {
int v=edge[i].v;
if(edge[i].c!=0||dep[v]!=-1) continue;
que[rear++]=v;
if(rear==maxn) rear=0;
dep[v]=dep[u]+1;
++gap[dep[v]];
}
}
}
int sap(int scr,int des) {
int res = 0;
bfs(scr,des);
int cur[maxn];
int S[maxn];
int top = 0;
memcpy(cur,head,sizeof(head));
int u=scr;
int i;
while(dep[scr]<n) {
if(u==des) {
int tmp = inf;
int inser;
for(i=0;i<top;i++)
if(tmp>edge[S[i]].c)
tmp=edge[S[inser=i]].c;
for(i=0;i<top;i++) {
edge[S[i]].c -= tmp;
edge[S[i]^1].c += tmp;
}
res += tmp;
top = inser;
u = edge[S[top]].u;
}
if(u!=des&&gap[dep[u]-1]==0) break;
for(i=cur[u];i!=-1;i=edge[i].next)
if(edge[i].c!=0&&dep[u]==dep[edge[i].v]+1)
break;
if(i!=-1) {
cur[u] = i;
S[top++] = i;
u = edge[i].v;
}
else {
int Min = n;
for(i=head[u];i!=-1;i=edge[i].next) {
if(edge[i].c==0) continue;
if(Min>dep[edge[i].v]) {
Min = dep[edge[i].v];
cur[u] = i;
}
}
--gap[dep[u]];
dep[u]=Min+1;
++gap[dep[u]];
if(u!=scr)
u=edge[S[--top]].u;
}
}
return res;
}
int g[55][55];
int m;
int main() {
while(~scanf("%d%d",&n,&m)) {
init();
int tot = 0 , i , j;
for1(i,n) for1(j,m) { scanf("%d",&g[i][j]); tot += g[i][j]; }
int s = 0 , t = n * m + 1;
for1(i,n) for1(j,m) {
int u = (i-1) * m + j;
if((i+j) % 2) {
addedge(s,u,g[i][j]);
if(i<n) addedge(u,u+m,inf);
if(i>1) addedge(u,u-m,inf);
if(j<m) addedge(u,u+1,inf);
if(j>1) addedge(u,u-1,inf);
}
else addedge(u,t,g[i][j]);
}
n = n*m+2;
int ans = sap(s,t);
printf("%d\n",tot - ans);
}
}