思路:
题目大意是一个棋盘上挖了几个洞,看剩下的点是否能根据覆盖规则完全匹配。
看到求图的完全匹配问题,就要想看是否能变形成二分图的最大匹配问题。
覆盖规则是上下左右任意两个相连的点,找一找这个小长方形的规律,可以发现:
任意的小长方形都是由一个奇数点+一个偶数点构成,且该两点必须相邻(上下左右)。
所谓奇数点就是该点坐标之和为奇数,偶数点就是该点坐标之和为偶数。
所以可以这么考虑:
将奇数点分为一类,将偶数点分为一类,两类的点与点若相连,说明它们可以构成一个小覆盖。题目就变成求所有的小覆盖的个数之和是否等于该题的最大覆盖数,即是否等于(n*m-k)/2。
即求二分图的最大匹配问题。
该题的难点就是如何转化并构建二分图。
源代码:
#include <iostream>
#include <fstream>
using namespace std;
int m, n, k;
int v1, v2;//奇数点个数,偶数点个数
int chessboard[35][35];
bool map[600][600];
int result;
bool visit[600];
int link[600];
bool dfs(int x)
{
for (int y = 1; y <= v2; y++)
{
if (map[x][y] && !visit[y])
{
visit[y] = true;
if (link[y]==0 || dfs(link[y]))
{
link[y] = x;
return true;
}
}
}
return false;
}
void search()
{
memset(link, 0, sizeof(link));
result = 0;
for (int x = 1; x <= v1; x++)
{
memset(visit, false, sizeof(visit));
if (dfs(x))
{
result++;
}
}
}
int main()
{
//ifstream in("input.txt");
while (cin >> m >> n >> k)
{
memset(chessboard, -1, sizeof(chessboard));
int row, col;
for (int i = 1; i <= k; i++)
{
cin >> col >> row;
chessboard[row][col] = 0;
}
if ((n*m - k) % 2 != 0)
{
cout << "NO" << endl;
continue;
}
v1 = v2 = 0;
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
if (chessboard[i][j] == -1)//跳过所有洞
{
if ((i + j) % 2 == 1)
{
chessboard[i][j] = ++v1;//奇数点从1开始标记,一共有v1个奇数点
}
else
{
chessboard[i][j] = ++v2;//偶数点从1开始标记,一共有v2个偶数点
}
}
}
}//end for
//构建二分图
memset(map,false,sizeof(map));
for (int i = 1; i <= m;i++)
{
for (int j = 1; j <= n; j++)
{
if ((i + j) % 2 == 0 || chessboard[i][j] == 0)
{//如果是偶数点 或者 是洞 ,跳过。因为要构建奇数点到偶数点的二分图。
continue;
}
//看该奇数点的上下左右是否能跟该奇数点连通(即如果不是坑就连通)
if (chessboard[i - 1][j] >= 1)
{//up
map[chessboard[i][j]][chessboard[i - 1][j]] = true;
}
if (chessboard[i + 1][j] >= 1)
{//down
map[chessboard[i][j]][chessboard[i + 1][j]] = true;
}
if (chessboard[i][j - 1] >= 1)
{//left
map[chessboard[i][j]][chessboard[i][j - 1]] = true;
}
if (chessboard[i][j + 1] >= 1)
{//right
map[chessboard[i][j]][chessboard[i][j + 1]] = true;
}
}
}
//Hungary Algorithm
search();
//Result
if (result == (n*m - k) / 2)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
//system("pause");
return 0;
}