题目
给定一个N行N列的棋盘,已知某些格子禁止放置。
求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。
输入格式
第一行包含两个整数N和t,其中t为禁止放置的格子的数量。
接下来t行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。
输出格式
输出一个整数,表示结果。
数据范围
1≤N≤100
思路
把坐标和为奇数的点视为棋盘的白色位置,偶数为黑色位置,跑一边二分图最大匹配即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define x first
#define y second
const int N=110;
int n,m;
pii match[N][N];
bool g[N][N], st[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool find(int x,int y)
{
for(int i=0;i<4;i++)
{
int a=x + dx[i], b = y + dy[i];
if(a && a<=n && b && b<=n && !g[a][b] && !st[a][b])
{
st[a][b]=true;
pii t=match[a][b];
if(t.x == -1 || find(t.x,t.y))
{
match[a][b]={x,y};
return true;
}
}
}
return false;
}
int main()
{
//freopen("test.in","r",stdin);//设置 cin scanf 这些输入流都从 test.in中读取
//freopen("test.out","w",stdout);//设置 cout printf 这些输出流都输出到 test.out里面去
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
while(m--)
{
int x,y;
cin>>x>>y;
g[x][y]=true;
}
memset(match,-1,sizeof match);
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)%2 && !g[i][j])
{
memset(st,0,sizeof st);
if(find(i,j)) res ++;
}
}
}
cout<<res<<endl;
return 0;
}