​方格取数(2)​

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7211    Accepted Submission(s): 2311



Problem Description


给你一个m*n的格子的棋盘,每个格子里面有一个非负数。

从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。


 


 


Input


包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)


 


 


Output


对于每个测试实例,输出可能取得的最大的和


 


 


Sample Input



3 375 15 21 75 15 28 34 70 5


 


 


Sample Output



188


 


 


Author


ailyanlu


 


 


Source


​Happy 2007​


 


  把横纵坐标之和按奇偶分成两组,然后对相邻的点连边的话会发现这是一个二分图,我们求得是最大独立集=|V|-最小覆盖集,最小覆盖集可以用网络流来求,左边集合向右边集合的连边容量为inf的边,S向左集合连边,右集合向T连边容量都是格子里的数,然后跑最大流就是


最小覆盖集了。


  


1 #include<bits/stdc++.h> 
2 using namespace std;
3 #define LL long long
4 #define mp make_pair
5 #define pb push_back
6 #define inf 0x3f3f3f3f
7 #define pii pair<int,int>
8 int first[3030],tot,S,T;
9 int cur[3030],d[3030];
10 bool vis[3030];
11 struct Edge{
12 int v,cap,flow,next;
13 }e[100010];
14 int fx[4][2]={-1,0,1,0,0,-1,0,1};
15 void add(int u,int v,int cap){
16 //cout<<"u="<<u<<' '<<v<<' '<<cap<<endl;
17 e[tot]=Edge{v,cap,0,first[u]};
18 first[u]=tot++;
19 e[tot]=Edge{u,0,0,first[v]};
20 first[v]=tot++;
21 }
22 int a[55][55];
23 bool bfs(){
24 memset(vis,0,sizeof(vis));
25 queue<int>q;
26 q.push(0);
27 d[0]=0;
28 vis[0]=1;
29 while(!q.empty()){
30 int u=q.front();
31 q.pop();
32 for(int i=first[u];~i;i=e[i].next){
33 if(!vis[e[i].v] && e[i].cap>e[i].flow){
34 vis[e[i].v]=1;
35 d[e[i].v]=d[u]+1;
36 q.push(e[i].v);
37 }
38 }
39 }
40 return vis[T];
41 }
42 int dfs(int x,int a){
43 if(x==T || a==0) return a;
44 int flow=0,f;
45 for(int &i=cur[x];~i;i=e[i].next){
46 if(d[x]+1==d[e[i].v] && (f=dfs(e[i].v,min(a,e[i].cap-e[i].flow)))>0){
47 e[i].flow+=f;
48 e[i^1].flow-=f;
49 flow+=f;
50 a-=f;
51 if(a==0) break;
52 }
53 }
54 return flow;
55 }
56 int solve(){
57 int ans=0;
58 while(bfs()){
59 for(int i=0;i<=T;++i)cur[i]=first[i];
60 ans+=dfs(0,inf);
61 }
62 return ans;
63 }
64 int main(){
65 int n,m,i,j,k;
66 while(scanf("%d%d",&n,&m)!=EOF){
67 LL s=0;
68 memset(first,-1,sizeof(first));
69 tot=0;
70 S=0,T=n*m+1;
71 for(i=1;i<=n;++i){
72 for(j=1;j<=m;++j){
73 scanf("%d",&a[i][j]);
74 s+=a[i][j];
75 int d1=(i-1)*m+j;
76 if((i+j)%2==0){
77 add(S,d1,a[i][j]);
78
79 for(k=0;k<4;++k){
80 int dx=i+fx[k][0];
81 int dy=j+fx[k][1];
82 if(dx>0&&dy>0&&dx<=n&&dy<=m){
83 int d2=(dx-1)*m+dy;
84 add(d1,d2,inf);
85 }
86 }
87 }
88 else{
89 add(d1,T,a[i][j]);
90 }
91 }
92 }
93 cout<<s-solve()<<endl;
94 }
95 return 0;
96 }