题目是中文的~
对于网格这种图是一个典型的二分图(只要无奇数长度的回路的图就是二分图),先建立二分图,对于第 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 ",tot-ret); } return 0; }