ACM_基础并查集
来源:互联网 发布:小米手机照片导入mac 编辑:程序博客网 时间:2024/05/22 00:05
基础并查集: 用于高效的查找某两个元素是否属于同一个集合;
一.普通的查找方式:
初始化所有的元素的父亲都是它自己:
for(int i = 1; i <= n; i++) pa[i] = i;find函数, 每次向上找它的父亲, 直到找到它的根(根的特点是pa[i] == i):
int find(int x){
return x == pa[x] ? x : find(pa[x]);
}- union_set函数:连接2个集合,实现的方法是用find函数找到2个集合的根分别为fx, fy, pa[fx] = fy; 就连接好了2个集合:
Void union_set(int x, int y){
int fx = find(x);
int fy = find(y);
pa[fx] = fy;
}
然后每次只需要判断一下是否find(x) == find(y)如果是说明他们是同一个集合, 否则不同集合;
二.并查集的实现方式:
- 和上面的方法大致相同, 唯一不同的是find函数; 每次find之后都把该集合的该支链的所有元素的父亲改成根节点;这样下次再find的时候只需要找一次就知道该元素属于哪个集合了;实现的方式也很相同,只需要把find函数稍微改一下:
int find(int x){
return x == pa[x] ? x : pa[x] = find(pa[x]);
}
当然这里树的深度还比较小了还不感觉什么, 但假如树足够深100层, 1000层的时候呢? 并查集会省下大量的时间;
例子
题目链接:http://poj.org/problem?id=1611
题目大意: 中文就不解释了;
做法:把同一个集合的所有元素都放到同一个集合里, 当放完之后, 检查一下0号同学在哪个集合, 再判断一下剩下的同学是否和它在同一个集合里面;
//// Created by fkjs on 2015-09-17// Copyright (c) 2015 fkjs. All rights reserved.////#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <sstream>#include <stack>#include <vector>#define clr(x) memset(x, 0, sizeof(x))using namespace std;const int INF = 0x3f3f3f3f;const int maxm = 505;const int maxn = 30000 + 10;typedef long long int ll;int n, m;int pa[maxn];int find(int x){//并查集的基础->find函数, 它的特点就是pa[x] = find(pa[x]), 这一语句可以把该路径上的所有点的父亲都改成根节点; return x == pa[x] ? x : pa[x] = find(pa[x]);}void connect(int x, int y){//链接两个并查集 int fa = find(x);//找到根节点, 当然找的过程中会更新路上的点; int fb = find(y);//同上; pa[fa] = fb;//链接两个集合;}int main(void) {#ifdef LOCAL //freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin); //freopen("C:\\Users\\Administrator\\Desktop\\out.txt", "w", stdout);#endif //ios_base::sync_with_stdio(0); while(scanf("%d%d", &n, &m) == 2 && (n || m)){ for(int i = 0; i < n; i++) pa[i] = i; for(int i = 0; i < m; i++){ int len; scanf("%d", &len); int x; scanf("%d", &x); int tp = x; for(int i = 1; i < len; i++){ scanf("%d", &x); connect(x, tp); tp = x; } } int ans = 0; int p = find(0);//找到最初感染者所在的集合, 它的根是p; for(int i = 0; i < n; i++)//凡是根是p的人都被感染了; if(find(i) == p) ans++; printf("%d\n", ans); } return 0;}
0 0
- ACM_基础并查集
- ACM_并查集
- ACM_并查集
- ACM_种类并查集
- ACM_模板_并查集
- ACM_并查集总结(转)
- 并查集基础
- 并查集基础
- 并查集基础
- 并查集基础
- 并查集基础
- 并查集基础
- 基础 并查集
- 并查集基础
- 并查集基础
- 并查集基础
- 并查集基础
- 查并集基础
- 视频无线传输的实现方式
- 第一阶段总结
- 360笔试--找老乡
- 关于netbeans下 启动Tomcat 失败
- 我的Docker学习之旅<二>
- ACM_基础并查集
- 白盒测试覆盖率概念普及
- DRAM knowledge
- mysql INSERT ... ON DUPLICATE KEY UPDATE
- android中textvie中的文字间距属性设置
- Xcode5和6上新建工程如何本地化启动页面
- 网站推荐(持续更新)
- mysql数据库字符编码选择导致的异常——\xE5\x8C\x97\xE4\xBA\xAC' for column
- DRAM knowledge2