题目来源:Light OJ 1356 Prime Independence
题意:给你n个数 选出最多的数构成一个集合使得任何2个数不是另外一个数的质数倍 x!=k*y
思路:矛盾的2个数连边 并且所有数分成质因子数为奇数和偶数两部分 以质因子奇偶不同构建二分图 同奇或者同偶的数一定不是另外一个数的质数倍
判断矛盾 首先对每个数因子分解 例如x 有a1个p1质因子 a2个p2质因子...an个pn质因子 x的质因子个数为a1+a2+...+an 记为sum
判断是否存在x/p1 x/p2 ...x/p3 存在并且他们的质因子个数sum奇偶性不同 连边 HK求最大独立集
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 500010;
const int maxm = 40010;
const int INF = 999999999;
struct edge
{
int v, next;
}e[maxn];
bool vis[maxn];
int prime[maxm];
int a[maxm];
int b[maxn];
int p[maxm];
int num[maxm];
int first[maxm], cnt;
int cx[maxm], cy[maxm];
int dx[maxm], dy[maxm];
int n, dis;
void sieve(int n)
{
int m = sqrt(n+0.5);
memset(vis, 0, sizeof(vis));
vis[0] = vis[1] = 1;
for(int i = 2; i <= m; i++)
if(!vis[i])
for(int j = i*i; j <= n; j += i)
vis[j] = 1;
}
int get_primes(int n)
{
sieve(n);
int c = 0;
for(int i = 2; i <= n; i++)
if(!vis[i])
prime[c++] = i;
return c;
}
void AddEdge(int u, int v)
{
e[cnt].v = v;
e[cnt].next = first[u];
first[u] = cnt++;
}
bool search()
{
dis = INF;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
queue <int> Q;
for(int i = 1; i <= n; i++)
{
if(cx[i] == -1 && (num[i]&1))
{
Q.push(i);
dx[i] = 0;
}
}
while(!Q.empty())
{
int u = Q.front(); Q.pop();
if(dx[u] > dis)
break;
for(int i = first[u]; i != -1; i = e[i].next)
{
int v = e[i].v;
if(dy[v] == -1)
{
dy[v] = dx[u] + 1;
if(cy[v] == -1)
{
dis = dy[v];
}
else
{
dx[cy[v]] = dy[v] + 1;
Q.push(cy[v]);
}
}
}
}
return dis != INF;
}
bool dfs(int u)
{
for(int i = first[u]; i != -1; i = e[i].next)
{
int v = e[i].v;
if(dy[v] == dx[u] + 1)
{
dy[v] = 0;
if(cy[v] == -1 || dfs(cy[v]))
{
cx[u] = v;
cy[v] = u;
//printf("**%d %d\n", u, v);
return true;
}
}
}
return false;
}
int match()
{
int ans = 0;
memset(cx, -1, sizeof(cx));
memset(cy, -1, sizeof(cy));
while(search())
{
for(int i = 1; i <= n; i++)
{
if(cx[i] == -1 && (num[i]&1) && dfs(i))
ans++;
}
}
return ans;
}
int main()
{
int cas = 1;
int T;
scanf("%d", &T);
int c = get_primes(500000);
while(T--)
{
scanf("%d", &n);
memset(b, 0, sizeof(b));
memset(num, 0, sizeof(num));
memset(first, -1, sizeof(first));
cnt = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
sort(a+1, a+n+1);
for(int i = 1; i <= n; i++)
{
b[a[i]] = i;
}
for(int i = 1; i <= n; i++)
{
int x = a[i];
int sum = 0;
int sum2 = 0;
for(int j = 0; j < c && prime[j]*prime[j] <= x; j++)
{
if(x % prime[j] == 0)
{
p[sum++] = prime[j];
while(x % prime[j] == 0)
{
x /= prime[j];
sum2++;
}
}
}
if(x > 1)
{
p[sum++] = x;
sum2++;
}
num[i] = sum2;
//printf("***%d\n", sum2);
for(int j = 0; j < sum; j++)
{
int temp = b[a[i]/p[j]];
if(temp > i)
continue;
if(temp)
{
if((sum2&1)==(num[temp]&1))
continue;
//printf("%d %d\n", i, temp);
if((sum2&1))
AddEdge(i, temp);
else
AddEdge(temp, i);
}
}
}
int ans = match();
printf("Case %d: %d\n", cas++, n-ans);
}
return 0;
}