并查集模板hdu-1213

目录

  • 例题:hdu 1213

    • 1、合并的优化
    • 2、查询的优化——路径的压缩
    • 3、优化完成的代码

例题:hdu 1213

//#include <bits/stdc++.h>
#include <iostream>
#include <stack>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <string.h>
using namespace std;

const int MAXN = 1005;
int s[MAXN];
void init_set(){
    for(int i = 1; i <= MAXN; i++)
        s[i] = i;
}

int find_set(int x){
    return x = s[x]? x: find_set(s[x]);
}

void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(x != y) s[x] = s[y];
}

int main(){
    int t, n, m, x, y;
    cin >> t;
    while(t--){
        cin >> n >> m;
        init_set();
        for(int i = 1; i <= m; i++){
            cin >> x >> y;
            union_set(x, y);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(s[i] == i) ans++;
        }
        cout << ans << endl;
    }
    return 0;
}

在上述程序中,find_set()、union_set()的搜索深度都是O(n),性能较差,下面进行优化,优化之后查找和合并的复杂度都是O(logn)。

1、合并的优化

在合并x 和 y时先搜到他们的根节点,然后再合并这两个根节点,即把一个根节点的集改成另一个根节点。这连个根节点的高度不同,如果把高度较小的那一个合并到较大的集上,能减小树的高度。下面是优化后的代码,再初始化时有height[i],定义元素i的高度。

int height[MAXN];
void init_set(){
    for(int i = 1; i <= MAXN; i++){
        s[i] = i;
        height[i] = 0;
    }
}

void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(height[x] == height[y]){
        height[x] = height[x] + 1;
        s[y] = x;
    }
    else{
        if(height[x] < height[y]) s[x] = y;
        else s[y] = x;
    }
}

2、查询的优化——路径的压缩

在上面的查询程序 find_set()中,查询元素 i 所属的集合需要搜索路径找到根节点,返回的结果也是根节点。这条路径可能很长。如果在返回的时候顺便把 i 所属的集改成根节点,那么下次搜索的时候在 O(1) 的时间内就能得到结果。

程序如下:

int find_set(int x){
    if(x != s[x])
        s[x] = find_set(s[x]);
    return s[x];

}

上面的代码用递归实现,如果数据规模太大,担心爆栈,可以用下面的非递归代码。

int find_set(int x){
    int r = x;
    while(s[r] != r)  //找到根节点
        r = s[r];
    int i = x, j;
    while(i != r){
        j = s[i];
        s[i] = r;
        i = j;
    }
    return r;
}

3、优化完成的代码

//#include <bits/stdc++.h>
#include <iostream>
#include <stack>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <string.h>
using namespace std;

const int MAXN = 1005;
int s[MAXN];
int height[MAXN];

void init_set(){
    for(int i = 1; i <= MAXN; i++){
        s[i] = i;
        height[i] = 0;
    }
}
int find_set(int x){
    int r = x;
    while(s[r] != r)  //找到根节点
        r = s[r];
    int i = x, j;
    while(i != r){
        j = s[i];
        s[i] = r;
        i = j;
    }
    return r;
}

void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(height[x] == height[y]){
        height[x] = height[x] + 1;
        s[y] = x;
    }
    else{
        if(height[x] < height[y]) s[x] = y;
        else s[y] = x;
    }
}

int main(){
    int t, n, m, x, y;
    cin >> t;
    while(t--){
        cin >> n >> m;
        init_set();
        for(int i = 1; i <= m; i++){
            cin >> x >> y;
            union_set(x, y);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(s[i] == i) ans++;
        }
        cout << ans << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lihello/p/11520738.html

时间: 2024-11-09 00:32:24

并查集模板hdu-1213的相关文章

【并查集】hdu 1272 小希的迷宫

[并查集]hdu 1272 小希的迷宫 并查集--并查集森林无环且连通 题目大意 给你连接关系构造一个图,判断图是否无环且满足连通性. 说一下思路 ①有无环:(a,b)元素a.b根节点是否相同,相同合并边就会成环,不满足题目要求 ②连通性:记录之前出现的节点,统计最后根节点==自身的节点个数,正好是1才是一片连通森林! ★再以后并查集初始化 i < _max,这道题有等号就WA了,不知道为什么??!!! 参考代码 //#pragma comment(linker, "/STACK:1024

并查集模板

//普通并查集模板 #include<iostream> using namespace std; const int MAX=10004; int fat[MAX];//存放每个节点的根节点 //找x的根节点并且把路径上的每个节点的父节点改成根节点 int find(int x) //while找根节点 { int rt=x; while(fat[rt]!=rt) rt=fat[rt]; int i=x,j; while(i!=rt){ j=fat[i]; fat[i]=rt; i=j; }

并查集 模板

const int MAX=1010;  //元素个数的最大值,根据题目修改int p[MAX];void init(int n) //n为实有元素个数{    for (int i=1; i<=n; i++)  p[i]=i;  }int find(int x) //查找{   if (x==p[x]) return x;    else  return  p[x]=find(p[x]);} void merge(int x,int y) //合并{   int px,py;    px=fi

【并查集】hdu 1856 More is better

[并查集]hdu 1856 More is better n个元素的集合应用问题--并查集. 题目大意 n个元素,告诉它们的两两连接关系,求单个连通分支所含元素个数的最大值 说一下思路 经典的并查集求的是所含连通分支的个数,这道题求的是并查集森林最大点集数(元素数),思路是维护一个cnt[ ]数组,初始化元素所在集合为自身cnt[ ] = 1;当要合并时,父节点累加孩子节点,cnt[ y ] += cnt [ x ],最后输出最大值. ★这题没有离散化就过了,so big the memory

【并查集模板】并查集模板 luogu-3367

题目描述 简单的并查集模板 输入描述 第一行包含两个整数N.M,表示共有N个元素和M个操作. 接下来M行,每行包含三个整数Zi.Xi.Yi 当Zi=1时,将Xi与Yi所在的集合合并 当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y:否则话输出N. 分析 简单的模板,解释留到算法微解读 AC代码 #include <bits/stdc++.h> using namespace std; int n,m; int fa[10000+5]; inline int read(){ int X

洛谷p3367 并查集模板

并查集是一种树型的数据结构,主要用来处理一些不相交集合的合并和更改问题. 比如找4的祖先,原来是 4->2->1,通过并查集路径压缩后,变为 4->1.也就变成了下图. 并查集的模板题: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; int dad[2000001]; int find(int x)//很简单的find函数,网上还

【带权并查集】HDU 3047 Zjnu Stadium

http://acm.hdu.edu.cn/showproblem.php?pid=3047 [题意] http://blog.csdn.net/hj1107402232/article/details/9921311 [Accepted] 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #incl

并查集问题hdu 1232

Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可).问最少还需要建设多少条道路? Input 测试输入包含若干测试用例.每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M:随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号.为简单起见,城镇从1

并查集模板、

并查集是一种用来管理元素分组情况的数据结构. 并查集的复杂度:并查集加入两个优化(路径压缩和高度的合并)以后效率很高,对n个元素的并查集进行一次操作的复杂度是O(a(n)).在这里,a(n)是阿克曼(Ackermann)函数的反函数,这比O(log(n))还快,不过这是“均摊复杂度”,也就是说不是每一次操作都满足这个复杂度,而是多次操作以后平均每一次的操作的复杂度是O(a(n)) 1 int par[MAX_N]; //父亲 2 int rank[MAX_N]; //树的高度 3 4 //初始化