LA3644 X-Plosives

这题是刘汝佳书中的并查集范例,我使用了《挑战程序设计竞赛》书上提供的并查集模板。当我们读到一道题的时候,在读懂题意后应该思考这个问题适用于哪种数据模型,并通过经验来判断使用何种算法,而不是无头苍蝇乱撞。
大致题意:每次给并查集中的数字使用一个并集操作,前提是这两个数字目前并不在同一个集合之中。可能比较含糊,看给出的测试用例:

1 2
3 4
3 5
3 1
2 3
4 1
2 6
6 5
-1

一点点来分析:1, 2并集操作,3, 4并集操作,3, 5并集。此时有两个集合,一个是(1, 2),另一个是(3, 4, 5)。不再赘述,以下每一行代表一次并集操作后的集合状态:

(1, 2)  (3, 4, 5)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5)  // 2 3在同一个集合里,所以不可以装sum++
(1, 2, 3, 4, 5)  // 4 1在同一个即合理,所以不可以装sum++
(1, 2, 3, 4, 5, 6) 
(1, 2, 3, 4, 5, 6)  // 6 5在同一个集合里,不可以装sum++

由此得到了数字3。
代码如下:

#define LOCAL

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_N = 100000 + 10;
int _par[MAX_N];                // 父亲
int _rank[MAX_N];               // 树的高度

// 初始化n个元素
void init(int n)
{
    for (int i = 0; i < n; i++)
    {
        _par[i] = i;
        _rank[i] = 0;
    }
}

// 查询树的根
int find(int x)
{
    if (_par[x] == x)
        return x;
    else
        return _par[x] = find(_par[x]);
}

// 合并x和y所属的集合
void unite(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x == y) return;

    if (_rank[x] < _rank[y]) {
        _par[x] = y;
    }
    else {
        _par[y] = x;
        if (_rank[x] == _rank[y])
            _rank[x]++;
    }
}

// 判断x和y是否属于同一个集合
bool same(int x, int y)
{
    return find(x) == find(y);
}
int main()
{
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif

    int a, b;
    while (cin >> a) {
        init(MAX_N);
        int res = 0;
        while (a != -1) {
            cin >> b;
            // 如果两个药品属于同一个
            if (same(a, b))
                res++;
            else
                unite(a, b);
            cin >> a;
        }
        cout << res << endl;
    }
    return 0;
}

上述解释已经很清楚了,不再罗嗦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值