1.コンセプト
ユニオン検索コレクションは、基本的にツリーの知識を使用します。セットの関連表現によく使用されます。一般的なバイナリツリーとは異なります。ユニオン検索コレクションは、親ノードへのポインタを使用します。分類に便利で、子ノードを見つけるのは簡単ではありません。
第二に、コードの実装
単純なユニオン検索、初期化、マージ、およびクエリには、主に3つの関数があります。
初期化する方法はたくさんあります。すべてをそれ自体に初期化できます。これは、開始状態で各ノードを個別のツリーとして扱うのと同じです。これらのツリーにはルートノードが1つしかないため、すべてが自分自身を指します。すべて-1に初期化することもできます。この初期化の利点は、このセットの最上位ノードにあるノードの数を節約できることです。
void init()
{
for(int i=1;i<=n;i++)
data[i]=i;
}
//初始化为自己
void init()
{
for(int i=1;i<=n;i++)
data[i]=-1;
}
//初始化为-1
マージは初期化の方法によって異なり、微妙な違いがありますが、主な考え方は同じです。2つのノードがセットに含まれているかどうかを比較します。含まれていない場合は、マージできることを意味します。検索機能を使用して、セットのルートノードを作成し、1つのルートノードが別のルートノードを指すようにすると、マージ操作を完了できます。
void merge(int x,int y)
{
int tx=find(x);
int ty=find(y);
if(tx!=ty)
data[tx]=data[ty];
//初始化为-1时可以补一句data[ty]+=data[tx],这样数组值的绝对值表示的就是集合中元素的个数
}
さまざまな初期化に応じて、さまざまな検索終了フラグを設定する必要があります。初期化を自己として使用する場合、検索の終了の兆候は、対応する位置の値がそれ自体の添え字に等しいことです。-1に初期化されると、検索の終了の兆候は、対応する位置の値がゼロ未満であることです。
int find(int x)
{
while(data[x]!=x)
x=data[x];
return x;
}
//初始化为自己
int find(int x)
{
while(data[x]>=0)
x=data[x];
return x;
}
int find(int n)
{
if(pre[n]==n)
return n;
else
return pre[n]=find(pre[n]);
}
//递归实现
コレクション自体を見つけることは難しくありません。BlueBridgeACMに携わっていた高齢者にとっては難しくありません。ただ、上向きに検索するプロセスを理解してください。完全なコードは次のとおりです
#include<bits/stdc++.h>
using namespace std;
int data[1005];
int m,n,choice=0;
void init()
{
for(int i=1;i<=n;i++)
data[i]=i;
}
int find(int x)
{
while(data[x]!=x)
x=data[x];
return x;
}
void merge(int x,int y)
{
int tx=find(x);
int ty=find(y);
if(tx!=ty)
data[tx]=data[ty];
}
int main()
{
scanf("%d %d",&m,&n);
init();
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d %d",&x,&y);
merge(x,y);
}
scanf("%d",&choice);
while(choice!=-1)
{
printf("%d\n",find(choice));
scanf("%d",&choice);
}
return 0;
}