【问题描述】
在一个有m * n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
【输入格式】
第1 行有2 个正整数m和n,分别表示棋盘的行数和列数。
接下来的m行,每行有n个正整数,表示棋盘方格中的数。
【输出格式】
将取数的最大总和输出
【输入样例】
3 3
1 2 3
3 2 3
2 3 1
【输出样例】
11
【数据范围】
1<=N,M<=30
正解:网络流
解题报告:对图进行黑白染色,然后就变成了一个二分图,然后就是套结论二分图最大独立集等于权值和减去最小割。
1 #include <iostream> 2 #include <iomanip> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cmath> 6 #include <cstring> 7 #include <string> 8 #include <algorithm> 9 #define RG register 10 #define MIN(a,b) a<b?a:b 11 const int N = 10000; 12 const int inf = 2147483641; 13 14 using namespace std; 15 16 int gi(){ 17 char ch=getchar();int x=0; 18 while(ch<'0' || ch>'9') ch=getchar(); 19 while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); 20 return x; 21 } 22 23 struct date{ 24 int from,to,val,fa; 25 }nn[N]; 26 27 int h[N],vis[N],f[N],head[N],cnt=1,jl[N],gg; 28 int S,T,ans,kk; 29 30 void link(int l,int r,int val){ 31 nn[++cnt]=(date){l,r,val,head[l]},head[l]=cnt; 32 nn[++cnt]=(date){r,l,0,head[r]},head[r]=cnt; 33 return; 34 } 35 36 int bfs(){ 37 for (RG int i=1; i<=gg; ++i) 38 vis[jl[i]]=0; 39 int l=0,r=1;gg=0; 40 h[1]=0,vis[0]=1; 41 while(l<r){ 42 ++l; 43 for (RG int i=head[h[l]]; i; i=nn[i].fa){ 44 if (nn[i].val==0 || vis[nn[i].to]) continue; 45 vis[nn[i].to]=vis[h[l]]+1,jl[++gg]=nn[i].to; 46 h[++r]=nn[i].to; 47 } 48 if (vis[T]) return 1; 49 } 50 return 0; 51 } 52 53 int dinic(int xh,int sum){ 54 if (xh==T) return sum; 55 RG int s=0; 56 for (RG int i=head[xh]; i; i=nn[i].fa){ 57 if (vis[nn[i].to]!=vis[xh]+1 || nn[i].val==0) continue; 58 RG int tmp=dinic(nn[i].to,MIN(sum,nn[i].val)); 59 nn[i].val-=tmp,nn[i^1].val+=tmp; 60 s+=tmp,sum-=tmp; 61 if (sum==0) break; 62 } 63 if (s==0) vis[xh]=-1; 64 return s; 65 } 66 67 int main(){ 68 freopen("x.in","r",stdin); 69 freopen("x.out","w",stdout); 70 int m=gi(),n=gi();T=n*m+1; 71 for (RG int i=1; i<=m; ++i){ 72 RG int k=(i-1)*n; 73 for (RG int j=1; j<=n; ++j){ 74 f[k+j]=gi();kk+=f[k+j]; 75 if ((i+j-1)&1){ 76 link(S,k+j,f[k+j]); 77 if (j<n) 78 link(k+j,k+j+1,inf); 79 if (i<m) 80 link(k+j,k+j+n,inf); 81 if (i>1) 82 link(k+j,k+j-n,inf); 83 if (j>1) 84 link(k+j,k+j-1,inf); 85 } 86 else 87 link(k+j,T,f[k+j]); 88 } 89 } 90 while(bfs()) ans+=dinic(S,inf); 91 printf("%d",kk-ans); 92 return 0; 93 }