Description
Driver Fang is given N nodes, each node is labeled with an integer between 1 and 1000000 (inclusive and labels are not necessarily distinct). Two nodes have an edge between them, if and only if the GCD (Greatest Common Divisor) of the labels of these nodes is greater than 1. Now, his task is to count the number of connected components in the graph.
Input
First line of the input T (T ≤ 10) denotes the number of cases. Then T cases follow. Each case consists of 2 lines. The first line has a number N (1 ≤ N ≤ 100000) denoting the number of nodes. The next line consists of N numbers. The i-th (1 ≤ i ≤ n) number Xi (1 ≤ Xi ≤ 1000000) denotes the label of the node i.
Output
For each case you have to print a line consisting consisting the case number followed by an integer which denotes the number of connected components. Look at the output for sample input for details.
Sample Input
2
3
2 3 4
6
2 3 4 5 6 6
Sample Output
Case 1: 2
Case 2: 2
题目大意,给出n个数,如果任意两个数的gcd >1那么他们之间有边相连,求联通块的个数。
题解:很明显的并查集,关键在于怎么判断两个数之间的gcd>1,如果直接用n^2的枚举算法,显然会超时。因此从他们的素因子入手。
可以这样想,把他们每个数的素因子分解出来,并把这个数和它们的素因子加入到一个并查集里去。数的大小是10^6规模,因此我们检测到10^3就够了
也就是检测1000以内的素数(因为如果存在1000以外的素因子y,那么肯定也存在1000以内的素因子x使得xy*...=num,因此我们可以通过求x的时候顺便把y求出来)
1000以内的素数只有168个。
核心就是:
void init()
{
for(int i = 1;i <= MAX;i++) parent[i] = i;
for(int i = 0;i < n;i++)
{
int tmp = arr[i];
for(int j = 0;j < pcnt;j++)
{
while(tmp%primes[j] == 0){
join(primes[j],arr[i]);
tmp /= primes[j];
if(tmp != 1) join(arr[i],tmp);
else break;
}
}
if(tmp > 1) join(tmp,arr[i]);
}
}
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int MAX = 1e7;
int arr[MAX+10];
int parent[MAX+5];
int n;
int primes[10005];
int pcnt;
int cccc[MAX];
void getprimes()
{
primes[pcnt++] = 2;
for(int i = 3;i <= 2000;i++)
{
int flag = 0;
for(int j = 2;j < i;j++)
{
if(i%j == 0)
{
flag = 1;
break;
}
}
if(!flag)
{
primes[pcnt++] = i;
}
}
//cout<<pcnt<<endl;
}
int find(int x) {
if (x != parent[x]) parent[x] = find(parent[x]);
return parent[x];
}
void join(int x1,int x2)
{
int p1 = find(x1);
int p2 = find(x2);
if(p1 != p2) parent[p1] = p2;
}
void init()
{
for(int i = 1;i <= MAX;i++) parent[i] = i;
for(int i = 0;i < n;i++)
{
int tmp = arr[i];
for(int j = 0;j < pcnt;j++)
{
while(tmp%primes[j] == 0){
join(primes[j],arr[i]);
tmp /= primes[j];
if(tmp != 1) join(arr[i],tmp);
else break;
}
}
if(tmp > 1) join(tmp,arr[i]);
}
}
int main()
{
getprimes();
int cas = 0;
int T;scanf("%d",&T);
while(T--)
{
memset(cccc,0,sizeof(cccc));
scanf("%d",&n);
for(int i = 0;i < n;i++) scanf("%d",&arr[i]);
init();
int ans = 0;
for(int i = 0;i < n;++i)
{
/*
if(arr[i] == 1){
ans++;
continue;
}
*/
if(cccc[find(arr[i])] == 0) ans++;
cccc[find(arr[i])] = 1;
}
printf("Case %d: %d\n",++cas,ans);
}
return 0;
}