题目背景
none!
题目描述
在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
输入格式
第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。
输出格式
程序运行结束时,将取数的最大总和输出
输入输出样例
输入 #1复制
3 3 1 2 3 3 2 3 2 3 1
输出 #1复制
11
说明/提示
m,n<=100
思路:
方格分为两部分,可以看成一个二分图,假设所有点都选,那么只要找出一部分不选的,使得这部分的值最小就可以。然后转换到了二分图的最小割上。起点和终点与点之间的连边的流量为点权,不选这个点,只要将这条边割掉就好。这个二分图的点的连边,表示两个点不能共存,所以目标是让加入起点和终点的图没有从起点到终点的路径,因此转换到了最小割。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<bitset>
#include<time.h>
using namespace std;
typedef long long ll;
const int inf=1e9+7;
struct node{
int v,nxt,w;
}e[1000005<<1];
int tot,head[10050];
int st,ed;
int dis[10050],q[10050];
void add(int u,int v,int w){
e[tot].v=v; e[tot].w=w; e[tot].nxt=head[u]; head[u]=tot++;
e[tot].v=u; e[tot].w=0; e[tot].nxt=head[v]; head[v]=tot++;
}
int bfs(int st,int ed){
for(int i=st;i<=ed;i++) dis[i]=-1;
int front=0,tail=0;
q[tail++]=st;
dis[st]=0;
while(front<tail){
int cur=q[front++];
if(cur==ed) return 1;
for(int i=head[cur];i!=-1;i=e[i].nxt){
if(e[i].w&&dis[e[i].v]<0){
q[tail++]=e[i].v;
dis[e[i].v]=dis[cur]+1;
}
}
}
if(dis[ed]==-1) return 0;
return 1;
}
ll dfs(int cur,int lim){
if(lim==0||cur==ed) return lim;
ll w,flow=0;
for(int i=head[cur];i!=-1;i=e[i].nxt){
if(e[i].w&&dis[e[i].v]==dis[cur]+1){
w=dfs(e[i].v,min(lim,e[i].w));
e[i].w-=w;
e[i^1].w+=w;
flow+=w;
lim-=w;
if(lim==0) break;
}
}
if(!flow) dis[cur]=-1;
return flow;
}
ll dinic(){
ll ans=0;
while(bfs(st,ed))
ans+=dfs(st,0x7fffffff);
return ans;
}
int n,m,x,nx[4][2]={0,1,0,-1,1,0,-1,0};
ll sum=0;
int id(int x,int y){
return (x-1)*m+y;
}
int main(){
cin>>n>>m;
ed=m*n+1;
for(int i=0;i<=ed+10;i++) head[i]=-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&x);sum+=x;
if((i+j)%2==1)
add(st,id(i,j),x);
else
add(id(i,j),ed,x);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if((i+j)%2==1){
for(int k=0;k<4;k++){
int tx=i+nx[k][0];
int ty=j+nx[k][1];
if(tx<=0||ty<=0||tx>n||ty>m)continue;
add(id(i,j),id(tx,ty),inf);
}
}
}
}
sum-=dinic();
printf("%lld\n",sum);
return 0;
}