题意:
一个n*m的棋盘上有t个坑,要求用1*2的纸条完全覆盖这个棋盘,纸条不能盖上坑。
要点:
这题是二分图,就是求二分图的最大匹配,看是否与棋盘格子数-坑数相等。但是具体的集合很难想,看了网上题解,确实比较精妙。首先我们知道如果一个格子的行数+列数i+j是奇数,它相邻的格子的i+j必定为偶数,所以我们只要用i+j为奇数的为一个集合,偶数为一个集合,求出最大匹配数即可。
15590489 | Seasonal | 2446 | Accepted | 940K | 219MS | C++ | 1508B | 2016-06-05 09:46:45 |
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 1500
bool map[N][N], used[N];
int girl[N],path[50][50];
int n, m,t,odd,even;
bool find(int x)
{
for (int i = 1; i < even; i++)
{
if (map[x][i] && used[i] == false)
{
used[i] = true;
if (girl[i] == -1 || find(girl[i]))
{
girl[i] = x;
return true;
}
}
}
return false;
}
void solve()
{
int ans = 0;
memset(girl, -1, sizeof(girl));
for (int i = 1; i < odd; i++)
{
memset(used, false, sizeof(used));
if (find(i)) ans++;
}
if (ans * 2 == (m*n - t))//如果最大匹配数*2与总格子数相等说明成功
printf("YES\n");
else
printf("NO\n");
}
int main()
{
int i, j;
while (~scanf("%d%d", &n, &m))
{
memset(path, 0, sizeof(path));
memset(map, false, sizeof(path));
scanf("%d", &t);
int y, x;
for (i = 0; i < t; i++)
{
scanf("%d%d", &x, &y);
path[y][x] = -1; //小心这里行列搞反
}
odd = even = 1;
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
{
if (path[i][j] != -1)
{
if ((i + j) % 2 == 1)//对应的奇数集合
path[i][j] = odd++;//进行标号
if ((i + j) % 2 == 0)//对应的偶数集合
path[i][j] = even++;
}
}
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
{
if (path[i][j] != -1 && (i + j) % 2 == 1)//(i+j)为奇数说明它四周都是偶数
{
if (path[i - 1][j] >= 1)
map[path[i][j]][path[i - 1][j]] = true;
if (path[i + 1][j] >= 1)
map[path[i][j]][path[i + 1][j]] = true;
if (path[i][j-1] >= 1)
map[path[i][j]][path[i][j-1]] = true;
if (path[i][j+1] >= 1)
map[path[i][j]][path[i][j+1]] = true;
}
}
solve();
}
return 0;
}