HDU1232 畅通工程

这题使用并查集来解决,先贴上代码:

#define LOCAL

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;

#define MAX_N 1005
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);
    //  freopen("output.txt", "w", stdout);
#endif
    int N, M;
    while (cin >> N >> M && N) {
        for (int i = 0; i < N; ++i)
            _par[i] = i;
        init(N);
        while (M--)
        {
            int x, y;
            cin >> x >> y;
            unite(x, y);
        }
        int num = -1;
        for (int j = 1; j <= N; ++j)
            if (_par[j] == j)
                num++;
        cout << num << endl;
    }
    return 0;
}

这是我之前贴在GitHub上的代码,今天翻以前校赛的题发现了这个就重新拿出来再看一看。并查集的这个代码是我从《挑战程序设计》上面抄下来的,集合了很多并查集的操作,可以直接使用。

======================更新======================
明白了如下代码段的用意:

for (int j = 1; j <= N; ++j)
    if (_par[j] == j)
        num++;

_par[j]中存储了每个节点的父亲节点,因为并查集的查找操作就是逐层向上找到祖先判断两个节点是否是同一祖先就判断出了是否是属于同一结合,所以如果某个节点的祖先如果是自己,那么说明这是一个联通分量,当联通分量为1的时候,num++结果为0,正好说明不需要修路。所以每增加一个连通分量,就要多修一条路以保证畅通,所以判断j的父节点是否等于j就可以找出连通分量的个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值