1. La primera es encontrar la plantilla optimizada. Si los datos no son grandes, combínelos directamente de forma manual y podrá utilizar el método de búsqueda
int find(int x){
while(x != p[x]){
p[x] = p[p[x]];
x = p[x];
}
return x;
}
Este método es adecuado para inicializar el valor p de cada nodo en sí mismo para evitar la explosión de la pila.
En segundo lugar, cuando hay más nodos y es necesario registrar el número de datos en cada colección, se utiliza la optimización del almacenamiento del número negativo del nodo raíz y cada vez que se fusiona en la rama más profunda del nodo.
void init(){
for(int i = 1; i <= n;i++){
p[i] = -1;
}
}
int find(int x){ //数据打了会爆栈
if(p[x] < 0)return x;
else return p[x] = find(p[x]);
}
int find2(int x) {
while(p[x] > 0 && p[p[x]] > 0){
p[x] = p[p[x]];
x = p[x];
}
return x;
}
void union_(int a, int b){
int p1 = find(a);
int p2 = find(b);
if(p[p1] < p[p2]){ //合并,p1顶点更多(负数),因此合并到p2上,减少查找次数
p[p2] += p[p1];
p[p1] = p2;
}else{ //将p2合并到p1集合,减少查找次数。
p[p1] += p[p2];
p[p2] = p1;
}
}
Mientras ahorra espacio de esta manera, también puede elegir la búsqueda recursiva o la búsqueda circular, y find2 evita la explosión de la pila.
Cada nodo raíz se inicializa a -1, lo que significa que solo hay un nodo en este conjunto, que es él mismo. Si un nodo no es el nodo líder de este conjunto, entonces su valor p es positivo, que es su nodo líder.
Ejemplo de código de tiempo de espera:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n, m;
int p[30005];
void init(){
for(int i = 0; i <= n;i++){
p[i] = -1;
}
}
int find(int x) {
// if(p[x] < 0)return x;
// return p[x] = find(p[x]);
int r = x;
while(p[r] >= 0) //以负数头下标为 记录节点数时,需要其前驱下标为0合法的情况,只有为负数才是头节点
r = p[r];
int i = x, j;
while(p[i] >= 0 && p[i] != r){
j = p[i];
p[i] = r;
i = j;
}
return r;
}
void un(int a, int b){//合并
int p1 = find(a);
int p2 = find(b);
if(p[p1] < p[p2]){
p[p2] += p[p1];
p[p1] = p2;
}else{
p[p1] += p[p2];
p[p2] = p1;
}
}
int main(){
int k, s, lid;
while(scanf("%d%d",&n,&m), n || m){
init();
for(int i = 1; i <= m;i++){
scanf("%d",&k);
scanf("%d",&lid);
for(int i = 1; i < k;i++){//少一个输入
scanf("%d", &s);
un(s, lid); //每一次输入都与第一个合并;最后直接找0的集合元素个数。
}
}
int t = find(0);
printf("%d\n", -p[t]);
}
return 0;
}
/*
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
*/