【网络流24题】方格取数问题

【问题描述】

在一个有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 }

 

posted @ 2017-02-22 09:48  Cjk_2001  阅读(420)  评论(0编辑  收藏  举报