题目:洛谷P2774、codevs1907。
题目大意:在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
解题思路:本题关键在建模。
把棋盘黑白染色(像国际象棋棋盘那样)。
对于黑色的,连接源点,容量为格子中的数。
对于白色的,连接汇点,容量为格子中的数。(黑白可以互换)
然后把所有黑点和相邻的白点连边,容量无穷大。
于是我们构造出了一个二分图。
题目说不能取相邻的格子,那么对于这张二分图来说,就不能让他有一条边有流经过(否则就取了两个相邻的格子了)。
于是求最小割即可。=求最大流
最后用总和减去最小割即可
C++ Code:
#include<cstdio> #include<cstring> #include<queue> #define inf 0x3fffffff std::queue<int>q; int n,m,cnt=-1,head[20005],iter[20005],level[20005]; struct edge{ int to,cap,nxt; }e[10005*8]; inline int number(int x,int y){ return(x-1)*m+y; } inline void addedge(int from,int to,int flow){ ++cnt; e[cnt]=(edge){to,flow,head[from]}; head[from]=cnt; ++cnt; e[cnt]=(edge){from,0,head[to]}; head[to]=cnt; } void bfs(int s){ level[s]=1; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].cap&&level[e[i].to]==-1){ level[e[i].to]=level[u]+1; q.push(e[i].to); } } } int dfs(int u,int t,int f){ if(u==t)return f; for(int& i=iter[u];i!=-1;i=e[i].nxt) if(e[i].cap&&level[u]<level[e[i].to]){ int d=dfs(e[i].to,t,e[i].cap>f?f:e[i].cap); if(d){ e[i].cap-=d; e[i^1].cap+=d; return d; } } return 0; } int maxflow(int s,int t){ for(int flow=0;;){ memset(level,-1,sizeof level); bfs(s); if(level[t]==-1)return flow; memcpy(iter,head,sizeof iter); int f; while(f=dfs(s,t,inf))flow+=f; } } int main(){ scanf("%d%d",&n,&m); int sum=0; memset(head,-1,sizeof head); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ int t; scanf("%d",&t); sum+=t; int p=number(i,j); if((i+j)&1){ addedge(0,p,t); if(i-1)addedge(p,number(i-1,j),inf); if(j-1)addedge(p,number(i,j-1),inf); if(i+1<=n)addedge(p,number(i+1,j),inf); if(j+1<=m)addedge(p,number(i,j+1),inf); }else addedge(p,n*m+1,t); } return!printf("%d ",sum-maxflow(0,n*m+1)); }