Problem Description
给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3 3 75 15 21 75 15 28 34 70 5
Sample Output
188
//
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=21010; const int M=250000; const int inf=(1<<28); int head[N]; struct Edge { int u,v,next,w; } edge[M]; int cnt,n,s,t;//n从0开始 0->n-1 void addedge(int u,int v,int w) { edge[cnt].u=u; edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].u=v; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++; } int sap() { int pre[N],cur[N],dis[N],gap[N]; int flow=0,aug=inf,u; bool flag; for(int i=0; i<n; i++) { cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=n; u=pre[s]=s; while(dis[s]<n) { flag=0; for(int &j=cur[u]; j!=-1; j=edge[j].next) { int v=edge[j].v; if(edge[j].w>0&&dis[u]==dis[v]+1) { flag=1; if(edge[j].w<aug) aug=edge[j].w; pre[v]=u; u=v; if(u==t) { flow+=aug; while(u!=s) { u=pre[u]; edge[cur[u]].w-=aug; edge[cur[u]^1].w+=aug; } aug=inf; } break; } } if(flag) continue; int mindis=n; for(int j=head[u]; j!=-1; j=edge[j].next) { int v=edge[j].v; if(edge[j].w>0&&dis[v]<mindis) { mindis=dis[v]; cur[u]=j; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return flow; } //初始化 cnt=0;memset(head,-1,sizeof(head)); //int u=i+j; u的奇偶性相同则不会相交,否则相交 int xx[4]={0,0,1,-1}; int yy[4]={1,-1,0,0}; int main() { int r,c; while(scanf("%d%d",&r,&c)==2&&r) { cnt=0; memset(head,-1,sizeof(head)); n=r*c+2; s=0,t=n-1; int sum=0; for(int i=1;i<=r;i++) { for(int j=1;j<=c;j++) { int x;scanf("%d",&x); sum+=x; int pos=(i-1)*c+j; if((i+j)%2) { addedge(s,pos,x); for(int k=0;k<4;k++) { int x=i+xx[k],y=j+yy[k]; if(x>=1&&x<=r&&y>=1&&y<=c) { addedge(pos,(x-1)*c+y,inf); } } } else addedge(pos,t,x); } } int ans=sap(); printf("%d\n",sum-ans); } return 0; }