最大公约数遍历

两个数的最大公因数大于一时,表示两个数连通
给一个数组,判断该数组是否全连通

1. 并查集

通过质因数间接合并数组中所有数

#define limit (int)1e5
vector<int> fac[limit + 10];//建立一个二维数组存储每一个数的全部质因数

// 全局预处理每个数的质因数,这里只处理一次,后面还能用到其他判例
int init = []() {
    for (int i = 2; i <= limit; i++) 
        if (fac[i].empty()) //表示该数为质因数
            for (int j = i; j <= limit; j += i) //给它的所有倍数添加该质因数
                fac[j].push_back(i);
    return 0;
}();

class Solution {
public:
    vector<int> parent;
    bool canTraverseAllPairs(vector<int>& nums) {
        int n = nums.size();
        int mx = *max_element(nums.begin(),nums.end());//限制一下可能得质因数范围,优化
        // 初始化并查集,应该包括数组所有数,以及可能的全部质因数,前n位表示数组数的集合,后mx位表示质因数集合
        //通过质因数集合来合并数组集合
        parent.resize(n+mx+1);
        iota(parent.begin(),parent.end(),0);

        // 对每个 nums[i],向它们的质因数连边
        for (int i = 0; i < n; i++) //对于数组每一个数
            for (int p : fac[nums[i]]) { //列举它的全部质因数
                unions(i,n+p);
        }
        // 检查是否所有位置点都在同一连通块内
        unordered_set<int> st;
        for (int i = 0; i < n; i++) st.insert(find(i));
        return st.size() == 1;
    }

    int find(int i){ //寻找集合首索引,即集合的唯一标识符
        if (parent[i] != i) parent[i] = find(parent[i]);  //如果自己不是,递归寻找且更新索引
        return parent[i];
    }
    void unions(int i ,int j){
        parent[find(i)] = parent[find(j)]; 
    }
};
posted @ 2023-05-31 00:38  失控D大白兔  阅读(10)  评论(0编辑  收藏  举报