给定一个 N 行 N 列的棋盘,已知某些格子禁止放置。
求最多能往棋盘上放多少块的长度为 2、宽度为 1 的骨牌,骨牌的边界与各线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。
输入格式
第一行包含两个整数 N 和 t,其中 t 为禁止放置的格子的数量。
接下来 t 行每行包含两个整数 x 和 y,表示位于第 x 行第 y 列的格子禁止放置,行列数从 1 开始。
输出格式
输出一个整数,表示结果。
数据范围
1≤N≤100,
0≤t≤100
输入样例:
8 0
输出样例:
32
分析:用的是匈牙利算法+二分图 ,遍历的时候只需遍历奇数格子就ok了,因为每个骨牌的摆放都会占用一个奇数格子和一个偶数格子
代码如下:
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
bool g[110][110],st[110][110];
PII coup[110][110];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int n,t,ans;
bool dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int x1=x+dx[i],y1=y+dy[i];
if(x1<1||x1>n||y1<1||y1>n)continue;
if(g[x1][y1]||st[x1][y1])continue;
st[x1][y1]=true;
PII tem=coup[x1][y1];
if(!tem.first||dfs(tem.first,tem.second))
{
coup[x1][y1]={x,y};
return true;
}
}
return false;
}
int main()
{
cin>>n>>t;
while(t--)
{
int x,y;
cin>>x>>y;
g[x][y]=true;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)%2&&!g[i][j])//因为每个骨牌的摆放都会占用一个奇数格子和一个偶数格子
{
if(dfs(i,j))ans++;
memset(st,0,sizeof st);//每次都需要清空st数组,因为匹配好的一对可能会有下家
}
}
}
cout<<ans;
return 0;
}