题目描述
在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
输入输出格式
输入格式:第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。
输出格式:
程序运行结束时,将取数的最大总和输出
输入输出样例
题解:
我们考虑这一个n*m的方格,我们首先对其进行黑白染色,从s连到黑色的点流量为点权,再从黑色的点连到白色的点流量为INF,然后再从白色的点连到t,流量也为点权。我们考虑一下,我们找出最小割,因为我们是把有公共边的两个点建的图,然后用总的减去最小割就是答案;
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define INF 2147483647
const int MAXN=1e6;
int mx[4]={0,0,1,-1};
int my[4]={1,-1,0,0};
int level[MAXN],n,m,head[MAXN],val,Total,cnt,s,t;
using namespace std;
struct Edge
{
int next,to,c,f;
}edge[MAXN];
inline void Add_Edge(int u,int v,int cc,int ff)
{
edge[cnt]=(Edge){head[u],v,cc,ff};
head[u]=cnt++;
}
bool Bfs(int s,int t)
{
memset(level,0,sizeof(level));
level[s]=1;
queue<int> que;
que.push(s);
while(!que.empty())
{
int c=que.front();
que.pop();
for(int i=head[c];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(level[v]==0&&edge[i].c>edge[i].f)
{
level[v]=level[c]+1;
que.push(v);
}
}
}
if(level[t]==0) return 0;
else return 1;
}
int Dfs(int u,int f)
{
if(u==t) return f;
int adf=0;
for(int i=head[u];i!=-1&&adf<f;i=edge[i].next)
{
int v=edge[i].to;
if(level[v]==level[u]+1&&edge[i].c>edge[i].f)
{
int temp=Dfs(v,min(f-adf,edge[i].c-edge[i].f));
edge[i].f+=temp;
edge[i^1].f-=temp;
adf+=temp;
}
}
return adf;
}
int Dinic(int s,int t)
{
int sumflow=0;
while(Bfs(s,t))
{
sumflow+=Dfs(s,INF);
}
return sumflow;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
s=0,t=n*m+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int val;
scanf("%d",&val);
Total+=val;
if(((i+j))%2==0) Add_Edge(s,(i-1)*m+j,val,0),Add_Edge((i-1)*m+j,s,0,0);
else Add_Edge((i-1)*m+j,t,val,0),Add_Edge(t,(i-1)*m+j,0,0);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i+j)%2==0)
for(int k=0;k<4;k++)
{
int nowx=i+mx[k];
int nowy=j+my[k];
if(nowx>=1&&nowx<=n&&nowy>=1&&nowy<=m)
{
Add_Edge((i-1)*m+j,(nowx-1)*m+nowy,1e8,0);
Add_Edge((nowx-1)*m+nowy,(i-1)*m+j,0,0);
}
}
}
}
printf("%d",Total-Dinic(s,t));
return 0;
}