1107 Clústeres sociales (30 puntos) [Método de escritura C ++ de búsqueda combinada no tradicional de Clase A PAT]

Todas las plantillas en línea utilizan la plantilla tradicional de colección de verificación de combinación. Para ser honesto, no me gusta el estilo de colección de verificación de combinación, así que después de estudiar durante una tarde, finalmente escribí la forma en que estaba satisfecho con la merge-check-collection (de hecho, es más como una simulación) Y la velocidad y la memoria también son excelentes.


La clave es: [el grupo social de una persona] y [el cuerpo del gráfico social de todos los fans de cada pasatiempo que le gusta] pertenecen al mismo Clúster Social,
es decir: dejar [la colección de una persona] y [le gusta] La colección de todos los fans de cada hobby de】 Merge (todos los fans se incluirán a sí mismos, no importa si no te ocupas de eso, saltar será más rápido) es nuestra tarea.


No utilice la búsqueda sindical tradicional

  • Use una hobby_loverlista de adyacencia para almacenar a todos los fanáticos de un pasatiempo determinado
  • Use una person_hobbylista de adyacencia para almacenar todos los pasatiempos de una determinada persona
  • Use mappara crear el [集合编号:集合]mapa (nombrado Cluster), con el primer conjunto de personas para ingresar el número como un conjunto de números, esa es Clusterla clave (y puede entenderse como la investigación enfocada en el nodo raíz)), en verificación y enfoque en diferente, habrá una colección de elementos que se cruzan , por lo que uso en vectorlugar setde;
  • Use setIDuna matriz para registrar el número de la colección donde se encuentra cada persona (también se puede entender como el nodo raíz de la colección de cheques combinada)
  • Para findFather()la operación de encontrar el nodo raíz del conjunto donde se encuentra un nodo en el conjunto de consultas combinado , puede usarlo directamente setID[某一个人的编号](la búsqueda es en realidad el número del conjunto) ------- y puede encontrar si dos elementos están en el mismo conjunto utilizado setID[a] == setID[b]para determinar
  • Y busque dos conjuntos de Union()operaciones de combinación de conjuntos , de hecho, los dos conjuntos de elementos vectordirectos push_backy pop_backbien tomados backse pueden hacer de forma combinada (dos conjuntos y compruebe que el enfoque no se cruza con el elemento)
# include <bits/stdc++.h>
using namespace std;

int N;
vector<int> hobby_lover[1010];  // 某一个爱好的每一个爱好者
vector<int> person_hobby[1010]; // 某一个人的每一个爱好
map<int, vector<int> > Cluster; // 以第一个加入集合的人作为集合的编号(键),值为一个社交团体集合
vector<int> setID(1010, 0); // 存放每个人所在的集合编号,为0说明集合不存在(这个人不存在于任何集合)

int main(){
    
    
    // 输入
    cin >> N;
    for(int person = 1;person <= N;++person){
    
    
        int K;
        scanf("%d: ", &K);
        for(int j = 0;j < K;++j){
    
    
            int hobby;
            cin >> hobby;
            hobby_lover[hobby].push_back(person); 
            person_hobby[person].push_back(hobby);
        }
    }
    // 算法开始
    for(int person = 1;person <= N;++person){
    
     // 遍历每一个人
    	// 【这个人】指代每一次的【person】
    	// 如果【这个人】没在任何集合那就让它自创一个集合,
    	// 于是他就一定是集合的根节点,于是它的编号也就是person值就是它所属集合的编号
        if(setID[person] == 0){
    
     
            setID[person] = person;
            Cluster[setID[person]].push_back(person);
        }
        for(int hobby: person_hobby[person]){
    
     // 遍历【这个人】的每一个爱好
            // 《某个爱好者》指代每一次的【lover】
            for(int lover: hobby_lover[hobby]){
    
     // 遍历【这个人】的某一个爱好的所有爱好者,让【这个人】和对应的爱好者并入一个集合
                if(setID[lover] == 0){
    
     // 如果《某个爱好者》没在任何集合,那就让他并入【这个人】所在的集合
                    setID[lover] = setID[person];
                    Cluster[setID[person]].push_back(lover);
                } 
                else {
    
     // 如果《某个爱好者》有所在集合,那就将《某个爱好者》所在的集合并入【这个人】所在的集合
                	if(setID[person] == setID[lover]) continue; // 如果两个要合并的集合是同一个集合,那就跳过
                    for(int i = Cluster[setID[lover]].size() - 1;i >= 0 ;i--){
    
    
                        int inp = Cluster[setID[lover]].back(); // 取得《某个爱好者》所在集合的成员
                        Cluster[setID[person]].push_back(inp);
                        Cluster[setID[lover]].pop_back();
                    }
                    Cluster.erase(setID[lover]); // 去掉被合并的集合
                    setID[lover] = setID[person]; // 合并后记得更新《某个爱好者》所在集合的编号为【这个人】的集合
                }
            }
        }
    }

    vector<int> rst;
    cout << Cluster.size() << endl;
    for(auto s: Cluster){
    
    
        rst.push_back(s.second.size()); // 统计每个社交团体的数量 
	}
    sort(rst.begin(), rst.end(), greater<int>());
    for(int i = 0;i < rst.size();++i){
    
    
        cout << rst[i] << (i == rst.size()-1 ? "\n" : " ");
    }
    
    return 0;
}

Inserte la descripción de la imagen aquí

/ *
gente aficionada
[1]: 7
[2]: 1
[3]: 3 5
[4]: 2 4 6 8
[5]: 3 7
[6]: 7
[7]: 1
[8]: 7
[ 9]:
[10]: 1
* /

/ *
gente afición
1: 2 7 10
2: 4
3: 5 3
4: 4
5: 3
6: 4
7: 6 8 1 5
8: 4
* /

Unión tradicional

Al principio, todo el mundo es un conjunto, y las personas con el mismo pasatiempo se fusionan
cada vez. Cada vez que person y hobby_person [hb] tienen el mismo pasatiempo hb, por lo que cada vez que se fusionan

# include <bits/stdc++.h>
using namespace std;

int N;
int father[1010];
int isRoot[1010];
int hobby_person[1010] = {
    
    0};

int findFather(int v){
    
    
    if(v == father[v]) return v;
    
    father[v] = findFather(father[v]);
    return father[v];
}

void Union(int a, int b){
    
    
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa != fb) father[fa] = fb;
}

void init(){
    
    
    for(int i = 1;i <= N;++i){
    
    
        father[i] = i;
        isRoot[i] = false;
    }
}

int main(){
    
    
    cin >> N;
    init();
    int K, hb;
    for(int person = 1;person <= N;++person){
    
     // 对每个人
        scanf("%d: ", &K);
        for(int j = 0;j < K;++j){
    
     // 对某个人的每个爱好
            cin >> hb;
            if(hobby_person[hb] == 0) // 让这个爱好的第一个爱好者成为一个社交圈子
                hobby_person[hb] = person;
            else // 合并有相同爱好hb的两个社交圈子
             	// Union(person, hobby_person[hb]); // 这么写也没问题,毕竟在Union函数中都会找到father的
             	Union(person, findFather(hobby_person[hb]));
        }
    }
    for(int i = 1;i <= N;++i)
        isRoot[findFather(i)]++;
    int cnt = 0;
    for(int i = 1;i <= N;++i)
        if(isRoot[i] != 0)
            cnt++;
    cout << cnt << endl;
    sort(isRoot+1, isRoot+N+1, greater<int>());
    for(int i = 1;i <= cnt;++i)
        cout << isRoot[i] << (i == cnt?'\n':' ');
    
    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/MYMarcoreus/article/details/113997038
Recomendado
Clasificación