Acwing 372 棋盘覆盖

题目链接

给定一个N行N列的棋盘,已知某些格子禁止放置。

求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。

输入格式

第一行包含两个整数N和t,其中t为禁止放置的格子的数量。

接下来t行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。

输出格式

输出一个整数,表示结果。

数据范围

1≤N≤100

输出样例:

8 0

输出样例:

32

 二分图匹配问题,把骨牌当作边,棋盘上的点当作图中的节点,棋盘中放置骨牌必须是两个相邻的点,而两个相邻的点的坐标和(x + y)的奇偶性不同,因此可以将所有的点通过坐标和的奇偶性分成两部分,看作是二分图的两个点集,再用匈牙利跑二分图就好了。建图的时候注意,因为我们跑最大匹配是从一个集合出发匹配另一个集合,而这个图我们需要跑所有的点,因此有两种解法。

1、遍历所有的点求最大匹配,结果除以2

2、只遍历二分图的左部或者右部(即奇偶性相同的一个点集)

我数组开小了,改bug改了好久QWQ

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 300;
int g[N][N];
int head[N * N], nex[N * N], to[N * N], cnt, match[N * N];
bool vis[N * N];
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
void init() {
	memset(g, 0, sizeof g);
	memset(head, -1, sizeof head);
	memset(nex, -1, sizeof nex);
	memset(vis, false, sizeof vis);
	memset(match, -1, sizeof match);
	cnt = 0;
}
void add(int a, int b) {
	cnt++;
	nex[cnt] = head[a];
	head[a] = cnt;
	to[cnt] = b;
}
bool dfs(int p) {
	for (int i = head[p]; i != -1; i = nex[i]) {
		int y = to[i];
		if (!vis[y]) {
			vis[y] = true;
			if (match[y] == -1 || dfs(match[y])) {
				match[y] = p;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int n, t;
	ios::sync_with_stdio(0);
	init();
	cin >> n >> t;
	while (t--) {
		int a, b;
		cin >> a >> b;
		g[a][b] = 1;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (g[i][j] == 0) {
				for (int k = 0; k < 4; k++) {
					int xx = i + dx[k];
					int yy = j + dy[k];
					if (xx >= 1 && xx <= n && yy >= 1 && yy <= n && g[xx][yy] == 0) {
						add((i - 1) * n + j, (xx - 1) * n + yy);
					}
				}
			}
		}
	}
	int res = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if ((i + j) % 2 == 1)continue;
			memset(vis, false, sizeof vis);
			if (dfs((i - 1) * n + j))res++;
		}
	}
	cout << res << "\n";
	return 0;
}
发布了143 篇原创文章 · 获赞 11 · 访问量 8194

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/103789231
今日推荐