上一篇文章我写了有关二分图的相关定理和公
式:http://blog.csdn.net/qq_34564984/article/details/52778763
而这道题,很显然,行+列为奇数和偶数的点是不会有边相连的,因此,可以将相邻
点建边,则此题为裸的求最大独立点权集的题
最大独立集+最小点权覆盖=总权值
最小点权覆盖=最小割=最大流
跑一遍最大流即可
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<climits>
#include<queue>
#define N 100001
#define M 400001
#define inf INT_MAX
using namespace std;
int n,S,T,all;
int map[50][50],m[50][50];
int id;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int head[N],pos,cur[N];
struct edge{int to,next,c;}e[M];
void add(int a,int b,int c)
{
e[pos].to=b,e[pos].next=head[a],e[pos].c=c,head[a]=pos;pos++;
e[pos].to=a,e[pos].next=head[b],e[pos].c=0,head[b]=pos;pos++;
}
void init()
{pos=0;memset(head,-1,sizeof(head));}
queue<int>Q;bool vis[N];int d[N];
bool bfs()
{
memset(vis,0,sizeof(vis));
vis[S]=1,d[S]=0;Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!vis[v]&&e[i].c>0)
{
vis[v]=1;
d[v]=d[u]+1;
Q.push(v);
}
}
}
return vis[T];
}
int dfs(int u,int a)
{
if(u==T||a==0)return a;
int f,flow=0;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c)))>0)
{
a-=f;
e[i].c-=f;
e[i^1].c+=f;
flow+=f;
if(a==0)break;
}
}
return flow;
}
int dinic()
{
int ans=0;
while(bfs())
{
for(int i=S;i<=T;i++)cur[i]=head[i];
ans+=dfs(S,inf);
}
return ans;
}
int main()
{
scanf("%d",&n);
S=0,T=n*n+1;
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
id++;m[i][j]=id;all+=map[i][j];
}
for(int u=1;u<=n;u++)
for(int v=1;v<=n;v++)
{
if((u+v)%2)
{
add(S,m[u][v],map[u][v]);
if(u>=2)add(m[u][v],m[u-1][v],inf);
if(v>=2)add(m[u][v],m[u][v-1],inf);
}
else
{
add(m[u][v],T,map[u][v]);
if(u>=2)add(m[u-1][v],m[u][v],inf);
if(v>=2)add(m[u][v-1],m[u][v],inf);
}
}
printf("%d\n",all-dinic());
}