给定一个N行N列的棋盘,已知某些格子禁止放置。
求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。
输入格式
第一行包含两个整数N和t,其中t为禁止放置的格子的数量。
接下来t行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。
输出格式
输出一个整数,表示结果。
数据范围
1 ≤ N ≤ 100
输出样例:
8 0
输出样例:
32
//
本题考查的是二分图匹配,因此我们可以考虑用匈牙利算法来解决这个问题
即然需要二分匹配,那么我们就得给这个图染个色才行,本题其实已经给我们染好色了~~
例:
我们将其横纵坐标加起来,就能发现其中的奥秘,**和为奇数点能与和为偶数的点匹配**,所就是说一个棋子一定覆盖一个和为偶数一个和为奇数的格子
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 110;
pair<int,int>match[N][N]; //存储和为偶数点匹配的点
int n,t;
bool g[N][N],st[N][N];
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
int find(int x,int y) //匈牙利算法
{
for(int i = 0; i < 4; i++)
{
int xx = x + dx[i] , yy = y + dy[i]; // 遍历四周
if(st[xx][yy] || g[xx][yy]) continue; //该点已被访问过 或 不能放棋子
if( xx >= 1 && xx <= n && yy >= 1 && yy <=n ) //判断越界
{
st[xx][yy] = true; //表示该点已被访问过
int tx = match[xx][yy].first , ty = match[xx][yy].second;
if( (tx == 0 && ty == 0) || find(tx,ty))
{
match[xx][yy] = {x,y}; //匹配这两个点
return true;
}
}
}
return false;
}
int solve()
{
int res = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n ;j++)
{
if(g[i][j]) continue;
if(( i + j ) % 2 == 0) //从奇数点开始匹配
{
memset(st,0,sizeof st);
if(find(i,j)) res++;
}
}
}
return res;
}
int main()
{
for(cin >> n >> t; t; t--)
{
int a,b;
cin >> a >> b;
g[a][b] = true; //标记不能放棋子的格子
}
cout << solve() << endl;
return 0;
}