题意:
给一串数,每一个数代表图的一个节点,然后两个数之间有除1之外的公因数表示这两个节点之间有边相连,求最大连通图。
做法:
如果平方找数两两之间是否存在公因数肯定超时,如果要判断两个数是否有公因数,只需要判断有没有含有相同的素数就可以了。
那么我们可以对每一个数进行一个归类,含有2的数,含有3的数,含有5的数,含有7的数。。。等等
对于都含有公因子2的数,那么肯定都相连。对于含有3的数,肯定也都相连。那么2和3这个群体相不相连呢?就得看有没有公共元素,所以这其实是一个很基础的并查集的模型。
怎么样合并呢?如果有a,b两个元素,那么我们只需要定义这两个元素的最终父亲是两个父亲间最小的那一个就ok。
代码:
class Solution {
public:
int all_num = 100000;
int prime[100005];
int fa[100005];
void get_prime(){//得到所有的素数
memset(prime,0,sizeof(prime));
vector<int>ans;
int len = 0;
for(int i=2;i<=all_num;i++){
if(!prime[i])ans.push_back(i),len++;
for(int j=0;j<len&&ans[j]*i<=all_num;j++){
prime[ans[j]*i] = 1;
if(i%ans[j]==0)break;
}
}
}
int get_father(int x){//路径压缩得到父亲
while(fa[x]!=x){
int f = fa[x];
fa[x] = fa[f];
x = f;
}
return x;
}
void init(){
for(int i=0;i<=all_num;i++)fa[i] = i;
}
int largestComponentSize(vector<int>& A) {
get_prime();
init();
int sz = A.size();
for(int i=0;i<sz;i++){
for(int d = 2;d*d<=A[i];d++){#如果遍历所有的素数会超时,因为素数有一万个。所以只能用根号的时间复杂度来遍历
if(A[i]%d==0&&!prime[d]){
int fa1 = get_father(A[i]);
int fa2 = get_father(d);
fa[fa1] = fa[fa2] = min(fa1,fa2);
}
if(A[i]%d==0&&!prime[A[i]%d]){
int fa1 = get_father(A[i]);
int fa2 = get_father(A[i]/d);
fa[fa1] = fa[fa2] = min(fa1,fa2);
}
}
}
map<int,int>ma; //最后用一个map来找到最终最大的集团,因为这个集团所有人的父亲都是同一个。
int mma = 0;
for(int i=0;i<sz;i++){
int fa1 = get_father(A[i]);
ma[fa1] = ma[fa1] + 1;
if(ma[fa1]>mma)mma = ma[fa1];
}
return mma;
}
};