使用并查集查找时,如果查找次数很多,那么使用朴素版的查找方式肯定要超时。比如,有一百万个元素,每次都从第一百万个开始找,这样一次运算就是10^6,如果程序要求查找个一千万次,这样下来就是10^13,肯定要出问题的。
这是朴素查找的代码,适合数据量不大的
int findx(int x)
{
int r=x;
while(parent[r] !=r)
r=parent[r];
return r;
}
下面是采用路径压缩的方法查找元素:
int find(int x) //查找x元素所在的集合,回溯时压缩路径
{
if (x != parent[x])
{
parent[x] = find(parent[x]); //回溯时的压缩路径
} //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
return parent[x];
}
上面是一采用递归的方式压缩路径, 但是,递归压缩路径可能会造成溢出栈,我曾经因为这个RE了n次,下面我们说一下非递归方式进行的路径压缩:
接下来是合并的代码,保证能够把小的子树接到大的子树上面
有很多组学生,在同一个组的学生经常会接触,也会有新的同学的加入。但是SARS是很容易传染的,只要在改组有一位同学感染SARS,那么该组的所有同学都被认为得了SARS。现在的任务是计算出有多少位学生感染SARS了。假定编号为0的同学是得了SARS的。
解题思路---->显然并查集了。并查集的详细解释在可以点击 并查集(不相交集合)进行学习。采用num[]存储该集合中元素个数,并在集合合并时更新num[]即可。然后找出0所在的集合的根节点x,因此,num[x]就是answer了。
- Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->#include <stdio.h>//by ktyanny
- #include <iostream>
- using namespace std;
- const int MAXN = 30001; /*结点数目上线*/
- int pa[MAXN]; /*p[x]表示x的父节点*/
- int rank[MAXN]; /*rank[x]是x的高度的一个上界*/
- int num[MAXN];/*num[]存储该集合中元素个数,并在集合合并时更新num[]即可*/
- void make_set(int x)
- {/*创建一个单元集*/
- pa[x] = x;
- rank[x] = 0;
- num[x] = 1;
- }
- int find_set(int x)
- {/*带路径压缩的查找*/
- /*保存待查找的数*/
- int r = x, temp;
- /*找到根节点*/
- while(pa[r] != r) r = pa[r];
- while(x != r)
- {
- temp = pa[x];
- pa[x] = r;
- x = temp;
- }
- return x;
- //if(x != pa[x]) //注释掉的其实也是可以的,不过不想用递归来做啦
- // pa[x] = find_set(pa[x]);
- //return pa[x];
- }
- /*按秩合并x,y所在的集合*/
- void union_set(int x, int y)
- {
- x = find_set(x);
- y = find_set(y);
- if(x == y)return ;
- if(rank[x] > rank[y])/*让rank比较高的作为父结点*/
- {
- pa[y] = x;
- num[x] += num[y];
- }
- else
- {
- pa[x] = y;
- if(rank[x] == rank[y])
- rank[y]++;
- num[y] += num[x];
- }
- }
- //answer to 1611
- int main()
- {
- int n, m, x, y, i, t, j;
- while(scanf("%d%d", &n, &m))
- {
- if(m==n && n == 0) break;
- if(m == 0)
- {
- cout << "1\n"; continue;
- }
- for(i = 0; i < n; i++)
- make_set(i);
- for(i = 0; i < m; i++)
- {
- scanf("%d", &t);
- scanf("%d", &x);
- for(j = 1; j < t; j++){
- scanf("%d", &y);
- union_set(x, y);
- x = y;
- }
- }
- x = find_set(0);/*找到0所在的树的树根*/
- //int ans = 0;
- //for(i = 0; i < n; i++)
- // if(pa[i] == x)
- // ans++;
- //cout << ans << endl;
- cout << num[x] << endl;
- }
- return 0;
- }
原文地址:https://www.cnblogs.com/downrainsun/p/9733647.html
时间: 2024-07-29 16:46:25