hdu1569-方格取数-二分图网络流
方格取数(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个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的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
Author
ailyanlu
Source
把横纵坐标之和按奇偶分成两组,然后对相邻的点连边的话会发现这是一个二分图,我们求得是最大独立集=|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 }