并查集是由一个数组pre[]
,和两个函数构成的,一个函数为find()
函数,用于寻找前导点的,第二个函数是join()
用于合并路线的。
初始化:将每个节点的前导节点设置为自己,如果未联通,将成独立点。
for(int i=0;i<n;i++)//n表示输入的结点的个数
pre[i]=i;//将每一个结点的前导点设置为自己
将x点直接与其根节点相连,构造成类似于只有叶子结点而没有分支的结点的树。
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];//找到他的前导结点
int i=x,j;
while(i!=r)//路径压缩算法(为了加快查找速度)
{
j=pre[i];//记录x的前导结点
pre[i]=r;//将i的前导结点设置为r根节点
i=j;
}
return r;
}
void join(int x,int y)
{
int a=find(x);//x的根节点为a
int b=find(y);//y的根节点为b
if(a!=b)//如果a,b不是相同的根节点,则说明ab不是连通的
{
pre[a]=b;//我们将ab相连 将a的前导结点设置为b
}
}
poj传染病的题
int find(int x)
{
if(x!=pre[x])
//找到其祖先节点
pre[x] = find(pre[x]);
//由父节点继续向上递归查询 ,并将其父节点变成找到的
return pre[x];
}
void merge(int x,int y)
{
//分别查询两点的祖先节点。
int prex = find(x);
int prey = find(y);
//如果二者的祖先节点不一致,那么任意让二者中某一个认另一个为祖先,保证同集合。
if(prex == prey)
{
return ;
}
//应该是祖先节点进行组合。而不是当前节点!
pre[prey] = prex;
a[prex] += a[prey];
}
int main()
{
int n,m;
int k,x,y;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
{
return 0;
}
for(int i=0;i<n;i++)
{
//先将自身作为祖先节点。
pre[i] = i;
a[i] = 1;
}
for(int i=0;i<m;i++)
{
//给出集合每个集合人数,以及第一个人的编号
scanf("%d%d",&k,&x);
k--;
while(k--)
{
scanf("%d",&y);
merge(x,y);
}
}
printf("%d\n",a[find(0)]);
}
return 0;
}