CodeForces 1021B. Chemical table(并查集)

题意:给定一个n * m的矩形,每个格子有两种颜色,一开始有t个格子上是黑色。对于任意的两行两列,如果交汇的四个格子中有三个是黑色,那么第4个会被自动变成黑色。问你至少需要手动涂黑几个格子,可以使得整个矩形内的格子都变成黑色。

分析:对于三个已经涂黑的格子((r1, c1)(r1, c2)(r2, c1)),会产生一个((r2, c2))的格子。相当于(r1-c1-c2)之间连了一条边,(r2-c1)又连了一条边,那么就会在(r2-c2)之间又连了一条边。我们可以看出是一个并查集问题,给每行每列一个编号,然后合并,对于一个集合来说,如果(p[i] = i),说明存在一个连通块,i是这个连通块的代表元素,假设我们最终得到了res个连通块,我们还需要在这些连通块涂(res - 1)个黑点,才能合并成一个连通块。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 400005;
int p[N];

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

int main()
{
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);

	for (int i = 1; i <= n + m; ++i) p[i] = i;

	int r, c;
	for (int i = 1; i <= q; ++i)
	{
		scanf("%d%d", &r, &c);
		c += n;
		p[find(r)] = find(c);
	}

	int res = 0;
	for (int i = 1; i <= n + m; ++i)
	{
		if (p[i] == i)
			++res;
	}

	printf("%d
", res - 1);


	return 0;
}
原文地址:https://www.cnblogs.com/pixel-Teee/p/13283914.html