LUOGU 3355 骑士共存问题 网络流24题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/90737835

title

LUOGU 3355
题目描述

在一个 n × n n \times n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入
在这里插入图片描述
对于给定的 n × n n \times n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击

输入输出格式
输入格式:

第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。

输出格式:

将计算出的共存骑士数输出

输入输出样例
输入样例#1:

3 2
1 1
3 3

输出样例#1:

5

analysis

简略题意:

求带障碍的 n × n n \times n 的国际象棋棋盘可以放多少个马,使得两两之间互相不能攻击。

又是一个最大独立集问题,套路。。

首先每个马只能攻击与自己颜色不同的格子。考虑二分图。。

还是老套路,将可以互相攻击的格子之间连一条边,然后求 二分图的最大独立集 即可。。

因为 (二分图)最大独立集 = 点数 - 最大匹配,所以我们只需要求出最大匹配就好了。。

详细的建图步骤和方格取数问题的步骤几乎一样,在此就不赘述了。。

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e4+10,maxm=4e5+10,maxk=210,inf=1e9;
const int dx[]={-2,-1,1,2,2,1,-1,-2},dy[]={1,2,2,1,-1,-2,-2,-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<<1],edge[maxm<<1],Next[maxm<<1],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 n,m;
inline int hash(int i,int j)
{
	return (i-1)*n+j;
}

bool ban[maxk][maxk];
int main()
{
	read(n);read(m);
	s=0,t=hash(n,n)+1;
	for (int i=1,x,y; i<=m; ++i) read(x),read(y),ban[x][y]=1;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=n; ++j)
		{
			if (ban[i][j]) continue;
			if ((i+j)&1)
			{
				add(s,hash(i,j),1);
				for (int k=0; k<8; ++k)
				{
					int fx=i+dx[k],fy=j+dy[k];
					if (fx<=0 || fx>n || fy<=0 || fy>n || ban[fx][fy]) continue;
					add(hash(i,j),hash(fx,fy),inf);
				}
			}
			else add(hash(i,j),t,1);
		}
	int ans=0;
	while (bfs()) ans+=get(s,inf);
	write(n*n-m-ans);
	return 0;
}

猜你喜欢

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