【SSL_1344】Knights

探讨在大小为nn的国际象棋棋盘上,部分格子被移除的情况下,如何放置最多的马使得它们不会互相攻击。通过构建图并使用匹配算法解决此问题。

Knights


Description

We are given a chess-board of size nn, from which some fields have been removed. The task is to determine the maximum number of knights that can be placed on the remaining fields of the board in such a way that none of them check each other.
一张大小为n
n的国际象棋棋盘,上面有一些格子被拿走了,棋盘规模n不超过200。马的攻击方向如下图,其中S处为马位置,标有X的点为该马的攻击点。
Fig.1: A knight placed on the field S checks fields marked with x.
Write a program, that:
reads the description of a chess-board with some fields removed, from the input file kni.in,
determines the maximum number of knights that can be placed on the chess-board in such a way that none of them check each other,
writes the result to the output file kni.out.
你的任务是确定在这个棋盘上放置尽可能多的马,并使他们不互相攻击。

Input

The first line of the input file kni.in contains two integers n and m, separated by a single space, 1<=n<=200, 0<=m<n2; n is the chess-board size and m is the number of removed fields. Each of the following m lines contains two integers: x and y, separated by a single space, 1<=x,y<=n – these are the coordinates of the removed fields. The coordinates of the upper left corner of the board are (1,1), and of the bottom right are (n,n). The removed fields are not repeated in the file.

Output

The output file kni.out should contain one integer (in the first and only line of the file). It should be the maximum number of knights that can be placed on the given chess-board without checking each other.

Sample Input

3 2
1 1
3 3

Sample Output

5

解题思路

先连边(黑连白),再套模板就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

long long n,m,a[2010][2010];
long long tot,hd[40010],cv[40010],fa[40010];

const int xn[9]={0,1,2,2,1,-1,-2,-2,-1};
const int yn[9]={0,2,1,-1,-2,-2,-1,1,2};

struct abc{
	int to,next;
}s[4000000];

long long hh(int x,int y)
{
	return (x-1)*n+y;
}

void add(int x,int y)
{
	s[++tot]=(abc){y,hd[x]};
	hd[x]=tot;
}

bool find(int x)
{
	for(int i=hd[x];i;i=s[i].next)
		if(!cv[s[i].to])
		{
			int y=s[i].to;
			cv[y]=1;
			int q=fa[y];
			fa[y]=x;
			if(q==0||find(q)) return 1;
			fa[y]=q;
		}
	return 0;
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		a[x][y]=1;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(!a[i][j]&&(i+j)%2==0)
				for(int k=1;k<=8;k++)
				{
					int x=i+xn[k],y=j+yn[k];
					if(x>0&&x<=n&&y>0&&y<=n&&!a[x][y])
						add(hh(i,j),hh(x,y));
				}
	long long ans=0;
	for(int i=1;i<=n*n;i++)
	{
		memset(cv,0,sizeof(cv));
		if(find(i)) ans++;
	}
	cout<<n*n-m-ans<<endl; 
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值