portals:372. 棋盘覆盖 - AcWing题库
思路:这道题目看起来真的是跟二分图一点关系,但偏偏就是能找到关系...
二分图匹配的模型有两个要素:
1.节点能分成两个独立的集合,每个集合内部没有边互相连接。
2.每一个节点只能与另一个集合有一条匹配边相连
在里面,有一个任意两张骨牌都不重叠,与要素2相对应,每一个骨牌都是由两个相邻方格构成,可以将骨牌看成一条边连接了两个方格。
有了边之后就要把边的两个端点划分成两个集合,这里可以把行号和列号加起来是偶数的格子看成集合1,加起来是奇数的看成集合2。最后会得到如下的一个图:
白色的是偶数格,黑色的是奇数格,可以发现,白色格子四个方向都是黑色格,黑色格子四个方向都是白色格子。四个方向也就是相当于连了四条边。
满足了要素1对于划分的两个独立集合中任意一个,同一个集合内没有边的要求。
另外,题目要求的某些个格子不能放就标记一下就可以了。
因此,这道题的难点反而是在建图上。
代码:
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define x first
#define y second
using namespace std;
typedef pair<int ,int>PII;
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};
int 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<1||a>n||b<1||b>n) continue;
if(g[a][b]||st[a][b]) continue;
st[a][b]=true;
PII t=match[a][b];
if(t.x==0||find(t.x,t.y))
{
match[a][b]={x,y};
return true;
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
g[x][y]=true;
}
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++;
}
printf("%d",res);
return 0;
}