版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/90736692
title
LUOGU 2774
题目背景
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
analysis
发现这道题和BZOJ 1324是完全一样的,模型为网络流的二分图最大点权独立集,这里也有个定理: 最大点权独立集=最大点权数-最大匹配数,最小割=最大流=最大匹配数。
然后就是建图的事了,我们对整个棋盘进行黑白染色(横纵坐标之和为奇数的为黑点),所以取一个黑点,受影响的便是周围的白点了。
然后我们就从
到
连
的边,
从
到
连
的边,
从
到
连
的边,
然后跑一边最大流,根据上面的定理输出答案即可。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e4+10,maxm=5e5+10,inf=1e9;
const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
template<typename T>inline void write(T x)
{
if (!x) { putchar('0'); return ; }
if (x<0) putchar('-'),x=-x;
T num=0,ch[20];
while (x) ch[++num]=x%10+48,x/=10;
while (num) putchar(ch[num--]);
}
int ver[maxm],edge[maxm],Next[maxm],head[maxn],len=1;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len;
}
int s,t;
int dist[maxn];
inline bool bfs()
{
queue<int>q;
memset(dist,0,sizeof(dist));
q.push(s);dist[s]=1;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (edge[i] && !dist[y])
{
dist[y]=dist[x]+1;
if (y==t) return 1;
q.push(y);
}
}
}
return 0;
}
inline int get(int x,int low)
{
if (x==t) return low;
int tmp=low;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (edge[i] && dist[y]==dist[x]+1)
{
int a=get(y,min(tmp,edge[i]));
if (!a) dist[y]=0;
edge[i]-=a;
edge[i^1]+=a;
if (!(tmp-=a)) break;
}
}
return low-tmp;
}
int m,n,sum,ans;
inline int hash(int i,int j)
{
return (i-1)*n+j;
}
int main()
{
read(m);read(n);
s=0,t=hash(m,n)+1;
for (int i=1; i<=m; ++i)
for (int j=1; j<=n; ++j)
{
int c;read(c);
sum+=c;
if ((i+j)&1) add(s,hash(i,j),c);
else add(hash(i,j),t,c);
}
for (int i=1; i<=m; ++i)
for (int j=1; j<=n; ++j)
{
if (!((i+j)&1)) continue;
for (int k=0; k<4; ++k)
{
int fx=i+dx[k],fy=j+dy[k];
if (!fx || fx>m || !fy || fy>n) continue;
add(hash(i,j),hash(fx,fy),inf);
}
}
while (bfs()) ans+=get(s,inf);
write(sum-ans);
return 0;
}