【思维题】CodeForce 1012B Chemical table

版权声明:Johnson https://blog.csdn.net/m0_38055352/article/details/91043904

这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!

一、题目大意

题目的大致意思是说,给定一个nm的矩阵,其中有q个元素已经拥有了,给出q个坐标,形如(r, c)表示r行c列已拥有,又知道如果(r1, c1)、(r1, c2)、(r2, c1)已知,可以产生(r2, c2),就是一个矩形的四个顶点元素,已知三个顶点元素可以产生另外一个,而且不会损耗原先的元素。题目问至少要增加多少元素才能保证nm的矩阵元素都拥有?

二、题目思路以及AC代码

这道题由数据量可知是不能由遍历矩阵入手的,因为遍历一次矩阵就已经超出时间限制了,所以我们只能从q个坐标入手。

考虑题目给出的产生元素的条件,我们可以换一个思路去理解,也就相当于,给你一个坐标(r1, c1),相当于告诉你r1和c1在同一个集合中,在告诉你(r1, c2)、(r2, c1),也就相当于告诉你r1和c2在同一个集合中,r2和c1在同一个集合中,这样自然r2和c2就在一个集合中了,也就实现了产生的关系,这两个模型可以说是一个意思。

这样的话,我们就只需要按照输入的q个坐标对n*m矩阵的行和列进行分集合操作,假设最后有C个集合,那么我们就需要最少C-1个点,才能将他们连接成一个集合,那么我们的答案也就是C-1了。

下面给出AC代码:

#include <iostream>
#define MAXN 200010
using namespace std;

int p[2 * MAXN];
bool vis[2 * MAXN];
int n, m, q;

void init() {
	for (int i = 0; i < 2 * MAXN; i++) {
		p[i] = i;
	}
}

int findRoot(int x) {
	if (p[x] == x) return x;
	else {
		return p[x] = findRoot(p[x]);
	}
}

void combine(int x, int y) {
	int xx = findRoot(x);
	int yy = findRoot(y);

	if (xx != yy) {
		p[xx] = yy;
	}
}

int main()
{
	init();

	cin >> n >> m >> q;

	for (int i = 0; i < q; i++) {
		int r, c;
		cin >> r >> c;
		combine(r, n + c);
	}

	int cnt = 0;
	for (int i = 1; i <= n + m; i++) {
		if (!vis[findRoot(p[i])]) {
			cnt++;
			vis[findRoot(p[i])] = true;
		}
	}

	cout << cnt - 1 << endl;

    return 0;
}

如果有问题,欢迎大家指正!!!

猜你喜欢

转载自blog.csdn.net/m0_38055352/article/details/91043904