题目是中文的~
对于网格这种图是一个典型的二分图(只要无奇数长度的回路的图就是二分图),先建立二分图,对于第 i 行第 j 列的点,i + j 为偶数的归为 x 集合,为奇数的归为 y 集合,相邻格子间连边,这就完成了二分图的构建。
题目要求取出来的值最大,且不能相邻,所以每一个点独立集都符合不相邻的要求,现在要使独立集的点权和最大,因为点独立集和点覆盖集是对应的,具体说一个图去掉任意一个点独立集剩下的点会构成一个点覆盖集,所以只需求最小点权覆盖即可。有关最小点权覆盖之前介绍过。。直接上代码吧。
#include <stdio.h>
#include <string.h>
#define Max 30
#define INF 5000000
int flow[Max*Max][Max*Max],d[Max*Max];
int N;
int sta,end;
int min(int a,int b)
{
if(a<b) return a;
else return b;
}
bool bfs(int s)
{
int front=0,rear=0;
int q[Max*100];
int k,i;
memset(d,-1,sizeof(d));
q[rear++]=s; d[s]=0;
while(front<rear)
{
k=q[front++];
for(i=1;i<=end;i++)
if(flow[k][i]>0&&d[i]==-1)
{
d[i]=d[k]+1;
q[rear++]=i;
}
}
if(d[end]>=0) return true;
return false;
}
int dinic(int k,int sum)
{
int i,a;
if(k==end) return sum;
int os=sum;
for(i=1;i<=end&∑i++)
if(d[i]==d[k]+1&&flow[k][i]>0)
{
a=dinic(i,min(sum,flow[k][i]));
flow[k][i]-=a;
flow[i][k]+=a;
sum-=a;
}
return os-sum;
}
int main()
{
int ret;
int tot;
int i,j;
int k;
while(scanf("%d",&N)!=EOF)
{
ret=0;
sta=0;end=N*N+1;
tot=0;
int now=1;
memset(flow,0,sizeof(flow));
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
{
scanf("%d",&k);
tot+=k;
if((i+j)%2==0)
{
flow[sta][now]=k;
if(j+1<=N) flow[now][now+1]=INF;
if(j-1>=1) flow[now][now-1]=INF;
if(i+1<=N) flow[now][now+N]=INF;
if(i-1>=1) flow[now][now-N]=INF;
}
else
flow[now][end]=k;
now++;
}
while(bfs(sta))
ret+=dinic(sta,INF);
printf("%d\n",tot-ret);
}
return 0;
}