CF1012B 化学桌

1 CF1012B 化学桌

2 题目介绍

时间限制 \(1s\) | 空间限制 \(512M\)

\(Innopolis\) 大学的科学家继续调查元素周期表。已知元素有 \(n·m\) 个,它们形成一个周期表:一个具有 \(n\) 行和 \(m\) 列的矩形。每个元素都可以通过表格中的坐标 \((r,c)(1≤r≤n,1≤c≤m)\) 描述。

最近,科学家发现,此表中每四个不同的元素形成一个矩形,且矩形的边与表的边平行,如果它们具有这四个元素中的三个的样本,则可以使用核聚变生成第四个元素的样本。因此,如果我们在位置 \((r1,c1),(r1,c2),(r2,c1)\) 中有元素,其中 \(r1≠r2\)\(c1≠c2\) 那么我们可以生成元素 \((r2,c2)\)

核聚变中使用的样品不会浪费,可以在以后的核聚变中再次使用。新制作的元素也可以在将来的核聚变中使用。

\(Innopolis\) 大学的科学家已经拥有 \(q\) 元素的样本。他们想要获得所有 \(n·m\) 个元素的样本。为此他们将从其他实验室购买一些样品,然后使用任意数量的核聚变以某种顺序生产所有剩余的元素。帮助他们找到需要购买的最少数量的元素。

3 题解

我们分析题目,发现:对于存在的三个点 \((x_1, y_1), (x_1, y_2), (x_2, y_1)\),点 \((x_2, y_2)\) 自动上色。我们观察这三个点:每个点都可以看作是一对横纵坐标的关系,而这三个点正好间接形成了一对 \(x_2\)\(y_2\) 的关系。因此,我们可以想到用并查集维护横坐标和纵坐标,每增加一个点就将这个点对应的横纵坐标加入同一集合中。当我们结束所有操作之后,如果剩下的集合数不为 \(1\),那么说明图上有一些点没有染色。此时,再在这些集合中任意选取一些节点连接,使得总集合个数变成 \(1\)。设集合数为 \(cnt\),那么答案就是 \(cnt - 1\)。注意这里我们给所有的纵坐标都加上一个 \(n\),便于和横坐标区分。

下面我给出做法正确性的具体证明:对于集合中的任意两个元素,如果他们之间直接有连接,那么该位置一定有一个上色的点。如果不直接连接,那么追根溯源一定能找到两个直接连接的元素,假如这两个元素又分别连着两个不同元素,那么这四个元素之间自动连接。这两个元素连接的两个不同元素就可以视作连接在了一起,这样一层一层递推,最终就可以给当前这个点上色。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 4e5+10;
int n, m, q, cnt;
int fa[N];
int u, v;
int find(int x)
{
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}
int main()
{
    cin >> n >> m >> q;
    for (int i = 1; i <= n+m; i++) fa[i] = i;
    for (int i = 1; i <= q; i++)
    {
        cin >> u >> v;
        int x = find(u), y = find(v+n);
        if (x == y) continue;
        fa[x] = y;
    }
    for (int i = 1; i <= n+m; i++) if (fa[i] == i) cnt++;
    cout << cnt-1;
    return 0;
}

欢迎关注我的微信公众号:智子笔记

posted @ 2021-02-09 21:36  David24  阅读(69)  评论(0编辑  收藏  举报