原则1:最终所需结果中,每个节点是否只与一条匹配边相连。
“任意两张骨牌都不重叠”说明每个格子只能被1张牌覆盖,而1张骨牌覆盖两个点,就是说一个格子a和格子b被同一张骨牌覆盖,则a就不能与格子c一起被骨牌覆盖;我们可以认为骨牌既是一条无向边,格子为节点,一个格子只能连一条边。
原则2:能把节点分成两个独立的集合,且对于答案要求的联系(认为有所需关系即两点间有边)集合内部有0条边。
注意到骨牌只能上下左右连接,而不能斜着,上下左右相当于节点减/加1,分奇偶性就可以把所有点分为两类,且类间无连接可能(即放骨牌)。
为什么能想到二分图最大匹配?
关键是分析出原则1的题目说明,满足了二分图的其中一个条件,在去思考原则2。
一般都是如此,二分图的难题都能从题目中分析出二分图两个原则的影子,再去往二分图上靠。
#include <cstring>
#include <iostream>
#include <algorithm>
#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}, dy[4] = {0, 1, 0, -1};
// dfs
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])//不是坏点 没遍历过
{
// 则男[x,y] 和 女[a,b]能够配对
st[a][b] = true;
PII t = match[a][b];//
//1 t.x==-1说明女[a,b]还没和其他人配对 则男[x,y]和女[a,b]可以直接配对
//2 女[a,b]已经有人配对,但和女[a,b]配对的男t还有其他选项
// 男t放弃和女[a,b]配对 让女[a,b]给男[x,y]配对(我感动了)
if (t.x == -1 || find(t.x, t.y))
{
match[a][b] = {x, y};
return true;
}
}
}
return false;
}
int main()
{
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);//每次都需要清空st数组,因为匹配好的一对可能会有下家
if(find(i,j))res++;//如果[i,j]能配对
}
}
}
cout << res << endl;
return 0;
}