[二分匹配]Chessboard

题目描述

一个的棋盘内,有些地方有洞,有些地方没有,没有洞的地方可以放东西,求是否可以用1*2的长方形填满所有格子(除了洞)。当然长方形不能相互覆盖。

输入输出格式

输入格式

第一行有三个整数:m,n,k(0<m,n<=32,0<=K<m*n),行数,列数和洞的数量。在接下来的k行中,每行都有一对整数(x,y),这表示第y行,第x列中有一个洞。

输出格式

如果可以覆盖该棋盘,则输出“YES”。否则,输出“NO”

输入输出样例

输入样例#1:

4 3 2
2 1
3 3

输出样例#1:

YES

说明

在这里插入图片描述
样例输入的解决方案。

题目解析

最大匹配
给棋盘中每个点标号
进行黑白描点,只有黑点才能够连白点
找黑点的4个方向,不越界且不是洞则连边
假设有k对匹配对,洞的数目为c,说明有2k个点匹配成功。
如果满足k
2+c=n*m,那么有解。

代码

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int m,n,k,u,v,ans;
int s[35][35],fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}},link[2005];
bool mapa[35][35],flag[2005];
vector<int> a[2005];
bool find(int x)
{
	for(int i=0;i<a[x].size();i++)
	 if(!flag[a[x][i]])
	 {
	    int j=a[x][i];
	    flag[j]=1;
	    int q=link[j];
	    link[j]=x;
	    if(!q||find(q)) return true;
	    link[j]=q;
	 }
	return false;
}//最大匹配
int main()
{
	cin>>m>>n>>k;
	for(int i=1;i<=k;i++)
	{
	  cin>>u>>v;
	  mapa[v][u]=1;
	}
	for(int i=1;i<=m;i++)
	 for(int j=1;j<=n;j++)
	  s[i][j]=(i-1)*n+j;//标号
	for(int i=1;i<=m;i++)
	 for(int j=1;j<=n;j++)
	  if(!mapa[i][j]&&(i+j)%2==0)//黑白描点,判断不为洞
	  {
	  	int xx,yy;
	  	for(int f=0;f<4;f++)//4个方向
	  	{
	  	  xx=i+fx[f][0];yy=j+fx[f][1];
	  	  if(xx<1||xx>m||yy<1||yy>n||mapa[xx][yy]) continue;//判断是否合法
	  	  a[s[i][j]].push_back(s[xx][yy]);//连边
		}
	  }
	for(int i=1;i<=m;i++)
	 for(int j=1;j<=n;j++)
	 {
	   memset(flag,0,sizeof(flag));
	   if(!mapa[i][j])
	    ans+=find(s[i][j]);
	 }
	if(ans*2+k==n*m)//判断是否有解
	 cout<<"YES";
	else 
	 cout<<"NO";
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/85199711