【网络流24题】No.9 方格取数问题 (二分图点权最大独立集)
【题意】
在一个有 m*n 个方格的棋盘中, 每个方格中有一个正整数。 现要从方格中取数, 使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。
输入文件示例
input.txt
3 3
1 2 3
3 2 3
2 3 1输出文件示例
output.txt
11
【分析】
方格的行列之和的奇偶构成二分图,转化成二分图点权最大独立集。
相邻的建边。
假设所有点都能取,
st->u 流量w[u] u的行列和为偶数
v->ed 流量为w[v] v的行列和为奇数
u,v相邻 u->v 流量为INF 表示若u->v 相邻,必定要去掉一个(即割掉与源点或汇点的一条边)
就是最小割。
用sum-最小割即为答案。
二分图点权最大独立集是很经典的模型。
傻逼的我还没看出来二分图以为会算重复,真是。。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 1010 10 #define INF 0xfffffff 11 12 struct node 13 { 14 int x,y,f,o,next; 15 }t[Maxn*1010];int len; 16 int first[Maxn]; 17 18 int mymin(int x,int y) {return x<y?x:y;} 19 int mymax(int x,int y) {return x>y?x:y;} 20 21 void ins(int x,int y,int f) 22 { 23 t[++len].x=x;t[len].y=y;t[len].f=f; 24 t[len].next=first[x];first[x]=len;t[len].o=len+1; 25 t[++len].x=y;t[len].y=x;t[len].f=0; 26 t[len].next=first[y];first[y]=len;t[len].o=len-1; 27 } 28 29 int st,ed; 30 queue<int > q; 31 int dis[Maxn]; 32 bool bfs() 33 { 34 while(!q.empty()) q.pop(); 35 memset(dis,-1,sizeof(dis)); 36 q.push(st);dis[st]=0; 37 while(!q.empty()) 38 { 39 int x=q.front(); 40 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 41 { 42 int y=t[i].y; 43 if(dis[y]==-1) 44 { 45 dis[y]=dis[x]+1; 46 q.push(y); 47 } 48 } 49 q.pop(); 50 } 51 if(dis[ed]==-1) return 0; 52 return 1; 53 } 54 55 int ffind(int x,int flow) 56 { 57 if(x==ed) return flow; 58 int now=0; 59 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 60 { 61 int y=t[i].y; 62 if(dis[y]==dis[x]+1) 63 { 64 int a=ffind(y,mymin(flow-now,t[i].f)); 65 t[i].f-=a; 66 t[t[i].o].f+=a; 67 now+=a; 68 } 69 if(now==flow) break; 70 } 71 if(now==0) dis[x]=-1; 72 return now; 73 } 74 75 void output() 76 { 77 for(int i=1;i<=len;i+=2) 78 printf("%d->%d %d\n",t[i].x,t[i].y,t[i].f); 79 } 80 81 int max_flow() 82 { 83 int ans=0; 84 while(bfs()) 85 { 86 ans+=ffind(st,INF); 87 } 88 return ans; 89 } 90 91 int bx[6]={0,0,1,0,-1}, 92 by[6]={0,1,0,-1,0}; 93 94 int main() 95 { 96 int n,m,sum=0; 97 scanf("%d%d",&n,&m); 98 st=n*m+1;ed=st+1; 99 for(int i=1;i<=n;i++) 100 for(int j=1;j<=m;j++) 101 { 102 int x,now=(i-1)*m+j; 103 scanf("%d",&x); 104 sum+=x; 105 if((i+j)%2==0) ins(st,now,x); 106 else ins(now,ed,x); 107 } 108 for(int i=1;i<=n;i++) 109 for(int j=1;j<=m;j++) 110 { 111 int now=(i-1)*m+j; 112 for(int k=1;k<=4;k++) if(i+bx[k]>=1&&i+bx[k]<=n&&j+by[k]>=1&&j+by[k]<=m) 113 { 114 int nn=(i+bx[k]-1)*m+j+by[k]; 115 if((i+j)%2==0) ins(now,nn,INF); 116 else ins(nn,now,INF); 117 } 118 } 119 int x=max_flow(); 120 printf("%d\n",sum-x); 121 return 0; 122 }
2016-11-04 15:32:42