并查集
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
附大佬博文: https://www.cnblogs.com/xzxl/p/7226557.html
题意:首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是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 }
附几乎和上题一样的题目 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 }
路径压缩: 附大佬博客 : 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];
}
}