并查集

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

 

附大佬博文:  https://www.cnblogs.com/xzxl/p/7226557.html

原题:杭电hdu1232畅通工程 

题意:首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路……

说明:输入4 2   1 3   4 3。即一共有4个点,2条路。下面两行告诉你,1、3之间有条路,4、3之间有条路。那么整幅图就被分成了1-3-4和2两部分。只要再加一条路,把2和其他任意一个点连起来,畅通工程就实现了,那么这个这组数据的输出结果就是1。好了,现在编程实现这个功能吧,城镇有几百个,路有不知道多少条,而且可能有回路。 这可如何是好? 我以前也不会呀,自从用了并查集之后,嗨,效果还真好!

附代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 100100;
 5 int pre[maxn];
 6 int ans;
 7 
 8 void init(int n)
 9 {
10     for(int i = 1; i <= n; i++)
11     {
12         pre[i] = i;
13     }
14 }
15 
16 int Find(int x)
17 {
18     while(x!=pre[x])
19     {
20         x = pre[x];
21     }
22     return x;
23 }
24 
25 void Union(int x,int y)
26 {
27     int a = Find(x);
28     int b = Find(y);
29     if(a != b)
30     {
31         ans--;
32         pre[a] = b;
33     }
34 }
35 
36 int main()
37 {
38     ios::sync_with_stdio(false);
39     cin.tie(0),cout.tie(0);
40     int n,u,v,m;
41     while(cin>>n&&n)
42     {
43         init(n);
44         cin>>m;
45         ans = n-1;
46         for(int i = 0; i < m; i++)
47         {
48             cin>>u>>v;
49             Union(u,v);
50         }
51         cout<<ans<<endl;
52     }
53     return 0;
54 }
View Code

 附几乎和上题一样的题目 hud1213

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define mem(a) memset(a,0,sizeof(a))
 5 #define ll long long
 6 const int maxn = 1100;
 7 int pre[maxn];
 8 int ans;
 9 
10 void init(int n)
11 {
12     for(int i = 1; i <= n; i++)
13     {
14         pre[i] = i;
15     }
16 }
17 
18 int Find(int x)
19 {
20     while(x != pre[x])
21     {
22         x = pre[x];
23     }
24     return x;
25 }
26 
27 void Union(int x,int y)
28 {
29     int a = Find(x);
30     int b = Find(y);
31     if(a!=b)
32     {
33         ans --;
34         pre[a] = b;
35     }
36 }
37 
38 int main()
39 {
40     ios::sync_with_stdio(false);
41     cin.tie(0),cout.tie(0);
42     int t,n,m,u,v;
43     cin>>t;
44     mem(pre);
45     while(t--)
46     {
47         cin>>n>>m;
48         init(n);
49         ans = n;
50         for(int i = 0; i < m; i++)
51         {
52             cin>>u>>v;
53             Union(u,v);
54         }
55         cout<<ans<<endl;
56     }
57     return 0;
58 }
View Code

 

 

路径压缩:  附大佬博客 :  https://blog.csdn.net/qq_19782019/article/details/78919990

int find(int x)
{
    while(x != pre[x])
    {
        pre[x] = pre[pre[x]];//路径压缩
        x = pre[x];
    }
    return x;
}



//递归压缩,查询更快一点
int find(int x)
{
    if(x == pre[x])
        return x;
    else
    {
        pre[x] = Find(pre[x]);
        return pre[x];
    }
}
View Code

 

posted on 2019-08-08 15:54  By_布衣  阅读(113)  评论(0编辑  收藏  举报

导航