一.题目描述
二.输入
10 8
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
三. 分析
这些元素可能处于这样的状态
1.初始状态即f[i]=i
2.已有父节点并且就是当前状态下真正的父节点
3.已有父节点但并非当前状态下真正的父节点,可能是以前的父节点,其父节点在merge时被合并,但是该节点未被合并。
第三种状态是常是令人担心的,比如在统计集合个数时和判断两个节点是否具有相同的父节点时,针对第一个问题,我们在统计存在几个集合时的方法巧妙,因为所有元素一开始的父节点都是自己,如果一旦存在父节点,那么改状态就会改变,即我们只需统计有多少个节点是自己,那么这就是集合个数,针对第二个问题,我们如果认真考察merge函数就会发现一旦某个节点自己或者其子节点被merge的话那么其父节点状态就会被更新成当前状态下真正的父节点,在小希的迷宫这道题目中,我们希望借助判断需要合并的两个节点是否具有相同的父节点来判断路径的唯一性,但是一开始考虑到两个节点的父节点状态可能并不是真正的父节点而是以前的父节点而导致这个方法没法用,但是如果清楚了我们一但要进行合并就立马回将其状态更新成其真正的父节点,那么这个问题就不存在了,所以我们在merge结束了以后一定还要将所有节点进行一次getf()这样便确保了所有节点的f[]是真正的f[]了
//
// main.cpp
// 并查集
//
// Created by 张嘉韬 on 16/3/18.
// Copyright © 2016年 张嘉韬. All rights reserved.
//
#include <iostream>
#include <cstring>
using namespace std;
int f[50];
void init(int n)
{
for(int i=1;i<=n;i++) f[i]=i;
}
int getf(int a)
{
if(f[a]==a) return a;
else
{
f[a]=getf(f[a]);
return f[a];
}
}
void merge(int a,int b)
{
int t1,t2;
t1=getf(a);
t2=getf(b);
if(t1!=t2)
{
f[t2]=t1;
}
}
void print(int n)
{
for(int i=1;i<=n;i++) cout<<"("<<i<<")"<<f[i]<<" ";
cout<<endl;
}
int main(int argc, const char * argv[]) {
freopen("/Users/zhangjiatao/Desktop/input.txt","r",stdin);
int n,m,a,b,sum;
sum=0;
cin>>n>>m;
init(n);
for(int i=1;i<=m;i++)
{
cin>>a>>b;
merge(a,b);
print(n);
}
for(int i=1;i<=n;i++)
{
f[i]=getf(i);
}
for(int i=1;i<=n;i++)
if(f[i]==i) sum++;
cout<<sum<<endl;
return 0;
}