LUOGU 2774 方格取数问题 网络流24题

版权声明: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是完全一样的,模型为网络流的二分图最大点权独立集,这里也有个定理: 最大点权独立集=最大点权数-最大匹配数,最小割=最大流=最大匹配数

然后就是建图的事了,我们对整个棋盘进行黑白染色(横纵坐标之和为奇数的为黑点),所以取一个黑点,受影响的便是周围的白点了。

然后我们就从 s 源点s 黑点 容量为点权 的边,
白点 t 汇点t 容量为点权 的边,
黑点 受他影响的白点 容量为正无穷 的边,
然后跑一边最大流,根据上面的定理输出答案即可。

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;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/90736692