这段时间要沉迷刷题一段时间了,就让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;
}
如果有问题,欢迎大家指正!!!