一名苦逼的OIer,想成为ACMer

Iowa_Battleship

JoyOI1035 棋盘覆盖

原题链接

对棋盘染色,坐标和为奇数的染黑,偶数为白。这时会发现对于相同颜色的格子,是无法放置骨牌的,这样我们就将所有格子分成两类,然后根据能否放置骨牌连边,最后就是求二分图最大匹配了。
这里我是用的匈牙利算法。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
int fi[N], di[N << 2], ne[N << 2], mtc[N], l, n;
bool v[N], a[110][110];
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
inline void add(int x, int y)
{
	di[++l] = y;
	ne[l] = fi[x];
	fi[x] = l;
}
inline int ch(int x, int y)
{
	return (x - 1) * n + y;
}
bool dfs(int x)
{
	int i, y;
	for (i = fi[x]; i; i = ne[i])
		if (!v[y = di[i]])
		{
			v[y] = 1;
			if (!mtc[y] || dfs(mtc[y]))
			{
				mtc[y] = x;
				return true;
			}
		}
	return false;
}
int main()
{
	int i, m, x, y, j, s = 0;
	n = re();
	m = re();
	for (i = 1; i <= m; i++)
	{
		x = re();
		y = re();
		a[x][y] = 1;
	}
	for (i = 1; i <= n; i++)
		for (j = 1; j <= n; j++)
			if (!((i + j) & 1) && !a[i][j])
			{
				x = ch(i, j);
				if (i - 1 && !a[i - 1][j])
					add(x, ch(i - 1, j));
				if (i + 1 <= n && !a[i + 1][j])
					add(x, ch(i + 1, j));
				if (j - 1 && !a[i][j - 1])
					add(x, ch(i, j - 1));
				if (j + 1 <= n && !a[i][j + 1])
					add(x, ch(i, j + 1));
			}
	for (i = 1, x = n * n; i <= x; i++)
	{
		memset(v, 0, sizeof(v));
		if (dfs(i))
			s++;
	}
	printf("%d", s);
	return 0;
}

posted on 2018-09-13 13:48  Iowa_Battleship  阅读(199)  评论(0编辑  收藏  举报

导航