题出问题:
前提:有1,2,3,4,5五点,2和3,3和4相通。
问1:5和1是否相通?
问2:如何使5个点全部相通?
并查集
1.介绍
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
这里用并查集解决连通之类的问题会更加简单,为了便于理解,在这里用数组来做简单的并查集。
2.实现代码
这里就不废话了,代码贴上来也不用看那麽多字。
int pre[1000 ];
int find(int x) //查找根节点
{
int r=x;
while ( pre[r] != r ) //返回根节点 r,因为只有根结点的值和下标是相 同的
r=pre[r];
int i=x , j ;
while( i != r ) //路径压缩,把记录的父节点直接变成根结点
{
j = pre[ i ]; // 在改变上级之前用临时变量 j 记录下他的值
pre[ i ]= r ; //把上级改为根节点
i=j;
}
return r ;
}
void join(int x,int y) //判断x y是否连通,
//如果已经连通,就不用管了 如果不连通,就把它们所 在的连通分支合并起,
{
int fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
3.在这里简单的解释下
这里的并查集实现主要是用数组来模拟,然后进行操作。真实的是树结构,有兴趣的可以继续研究。
这里的数组的下标对应的是图的第几个节点,值代表当前的节点的父节点的位置。
当然在压缩路径之后父节点都是根结点。这里便于搜索,否则出现了一字长蛇阵搜索就是很浪费时间。
这里就可以得出了前面的答案:
1.搜索两点是否连通时,只要看两者父节点是否相同,也就是值是否相同。
2.连通时,只要包根结点连接,就是调用jion方法即可。
join时这里可以随便的连接根结点,但是在树中,要把深度低的树加到深度高的树,这样总体的树的深度不会增长。
简单的并查集题目
2015年第五届ACM趣味编程循环赛(第一场) by LeiQ
Problem Description
小雷有个特殊的癖好,平时喜欢收藏冰茶几!
顾名思义,这些茶几被冰冻住了,因此一套冰茶几分为好几部分,并且如果茶几A与B冻在一起,B与C冻在一起,那么A与C也就冻在了,即冰冻状态有传递性,ABC此时会看作一个整体。
为了保证冰茶几的完整性,小雷每次只能移动一整块冰茶几,也就是冰冻在一起的一部分。小雷想知道他需要搬几次才能全部搬到实验室,你能帮小雷快速计算出答案么?
Input
多组输入,先输入组数T(1 < = T < = 200)。
对于每组输入,先输入一个整数n(1 < = n < = 100000),k(0 < = k < = 100000),总共有n个茶杯,茶几编号1~n。
之后k行,每行两数x,y(1 < = x,y < = n),表示第x个茶几和第y个茶几冰冻在一起。
Output
对于每组输入,先输出”Case z: ”(不带引号)表示组数,再输出一个整数,表示小雷需要搬动的次数。
Sample Input
3
3 1
1 2
5 2
1 2
3 4
5 2
1 2
2 3
Sample Output
Case 1: 2
Case 2: 3
Case 3: 3
简单的代码实现,有兴趣的同学可以优化一下时间。
void join(int x,int y) //判断x y是否连通,
//如果已经连通,就不用管了 如果不连通,就把它们所 在的连通分支合并起,
{
int fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
public static int select(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == i) {
sum++;
}
}
return sum;
}
public static void main(String[] args) {
int group; //输入的组数
Scanner input = new Scanner(System.in);
group = input.nextInt();
int count = 1;
while (count <= group) {
int number = input.nextInt();
int key = input.nextInt();
int[] arr = new int[number + 1];
for (int i = 1; i < number; i++)
arr[i] = i;
while (key != 0) {
int x = input.nextInt();
int y = input.nextInt();
join(x,y)
key--;
}
System.out.println("Case " + count + ": " + select(arr));
count++;
}
}