方格取数 3
时间限制: 2 s
空间限制: 256000 KB
题目描述 Description
在一个有m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任
意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。
编程任务:
对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
输入描述 Input Description
第1 行有2 个正整数m和n,分别表示棋盘的行数
和列数。接下来的m行,每行有n个正整数,表示棋盘方格中的数。
输出描述 Output Description
将取数的最大总和输出
样例输入 Sample Input
3 3
1 2 3
3 2 3
2 3 1
样例输出 Sample Output
11
数据范围及提示 Data Size & Hint
n,m<=30
最小割。由于题目要求不能选择相邻的两个数,我们可以考虑给棋盘染色,白格子只与黑格子相邻,反之亦然。源点都和某一种颜色的格子相连,汇点和另一种颜色的格子相连,权值为格子里的数。相邻两个格子之间建一条流量为无穷大的边,这样就保证最小割只会选择去除与源点或汇点相邻的边,而去除这条边就意味着不选这个格子里的数。最后当最小割选择完成后,源点和汇点没有路径相连,这就意味着没有相邻的格子被同时保留。(因为源点和汇点连接必须要经过相邻格子之间的边,而现在源点和汇点不相连,就意味着一旦某一个格子被选择,它周围的格子都不能再被选择了)。
#include<bits/stdc++.h> #define N 1000 using namespace std; long long tot=0; typedef struct{long long v,flow;}ss; vector<long long>edges[N]; ss edg[N*N]; long long dis[N]; long long S,T; long long current[N]; void addedge(long long u,long long v,long long flow) { edg[tot]=(ss){v,flow}; edges[u].push_back(tot++); edg[tot]=(ss){u,0}; edges[v].push_back(tot++); } bool bfs() { queue<long long>q; q.push(S); for(long long i=0;i<N;i++)dis[i]=LLONG_MAX/2; dis[S]=1; while(!q.empty()) { int now=q.front(); q.pop(); long long Size=edges[now].size(); for(long long i=0;i<Size;i++) { ss &e=edg[edges[now][i]]; if(e.flow>0&&dis[e.v]==LLONG_MAX/2) { dis[e.v]=dis[now]+1; q.push(e.v); } } } if(dis[T]==LLONG_MAX/2)return 0; return 1; } long long dfs(long long x,long long flow) { if(x==T)return flow; long long Size=edges[x].size(); for(long long i=current[x];i<Size;i++) { current[x]=i; ss &e=edg[edges[x][i]]; if(dis[x]+1==dis[e.v]&&e.flow>0) { long long Flow=dfs(e.v,min(flow,(long long)e.flow)); if(Flow!=0) { e.flow-=Flow; edg[edges[x][i]^1].flow+=Flow; return Flow; } } } return 0; } long long dinic() { long long ans=0; while(bfs()) { memset(current,0,sizeof(current)); long long flow; while(flow=dfs(S,LLONG_MAX))ans+=flow; } return ans; } int main() { int m,n,t=0; int Map[35][35]; int num[35][35]; long long ans=0; scanf("%d %d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { scanf("%d",&Map[i][j]); num[i][j]=t++; ans+=Map[i][j]; } S=t++; T=t++; for(int i=1;i<=m;i++) { for(int j=(i+1)%2+1;j<=n;j+=2) { addedge(S,num[i][j],Map[i][j]); if(i-1>=1)addedge(num[i][j],num[i-1][j],LLONG_MAX/2); if(i+1<=m)addedge(num[i][j],num[i+1][j],LLONG_MAX/2); if(j-1>=1)addedge(num[i][j],num[i][j-1],LLONG_MAX/2); if(j+1<=n)addedge(num[i][j],num[i][j+1],LLONG_MAX/2); } } for(int i=1;i<=m;i++) { for(int j=i%2+1;j<=n;j+=2) { addedge(num[i][j],T,Map[i][j]); } } printf("%lld",ans-dinic()); return 0; }