POJ2446 Chessboard(二分图)

题意:

一个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;
}



posted @ 2016-06-05 10:06  seasonal  阅读(99)  评论(0编辑  收藏  举报