题意:给出n个数,求最大集合,这个集合要求满足:任意两个元素a,b,当a % b == 0 && a / b == k,若k是质数,则a,b不能同时在这个集合内
题解:最大独立子集问题,建一个二分图。当a的质因子等于b的质因子数+1的时候,即a,b的质因子数的奇偶性不同时,那么a,b就能建立关系。建好图后,最大独立集 = 点数 - 最大匹配。由于这题的数据两有点大,匈牙利算法应该会TLE,所以要用HK算法(Hopcroft-Karp算法)
代码
#include<cstdio>
#include<cstring>
#include<queue>
#define M 500010
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int to;
int next;
}edge[M];
int head[M];
int cnt;
int prime_num[M];
int pos;
int prime_factor[M];
int a[M], b[M];
int amount, emount;
int n;
bool used[M];
int dx[M], dy[M];
int mx[M], my[M];
int id[M];
int dis;
void prime()
{
for(int i = 1; i < M; i++)
{
int n = i, x = 0;
for(int j = 2; j * j <= n; j++)
{
if(n % j == 0)
{
while(n % j == 0)
{
x++;
n = n / j;
}
}
}
if(n != 1)x++;
prime_num[i] = x;
}
}
void get_prime_factor(int x)
{
pos = 0;
for(int i = 2; i * i <= x; i++)
{
if(x % i == 0)
{
prime_factor[pos++] = i;
while(x % i == 0)
x /= i;
}
}
if(x > 1)
prime_factor[pos++] = x;
}
void addedge(int u, int v)
{
edge[cnt].to = v;
edge[cnt].next = u;
edge[cnt].next = head[u];
head[u] = cnt;
cnt++;
}
bool bfs()
{
queue<int> Q;
dis = INF;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
for(int i = 1; i <= amount; i++)
if(mx[id[i]] == -1)
{
Q.push(id[i]);
dx[id[i]] = 0;
}
while(!Q.empty())
{
int u = Q.front();
Q.pop();
if(dx[u] > dis)break;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(dy[v] == -1)
{
dy[v] = dx[u] + 1;
if(my[v] == -1)
dis = dy[v];
else
{
dx[my[v]] = dx[u] + 1;
Q.push(my[v]);
}
}
}
}
return dis != INF;
}
bool dfs(int u)
{
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(!used[v] && dy[v] == dx[u] + 1)
{
used[v] = true;
if(my[v] == -1 || dfs(my[v]))
{
my[v] = u; mx[u] = v;
return true;
}
}
}
return false;
}
int main()
{
prime();
int T;
scanf("%d", &T);
for(int t = 1; t <= T; t++)
{
scanf("%d", &n);
amount = emount = 0, cnt = 0;
memset(head, -1, sizeof(head));
memset(b, 0, sizeof(b));
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[a[i]] = i;
if(prime_num[a[i]] % 2)
id[++amount] = i;
}
for(int i = 1; i <= n; i++)
{
get_prime_factor(a[i]);
for(int j = 0; j < pos; j++)
{
int x = a[i] / prime_factor[j];
if(b[x])
{
if(prime_num[a[i]] % 2 != prime_num[a[b[x]]] % 2)
{
addedge(i, b[x]);
addedge(b[x], i);
}
}
}
}
int ans = 0;
memset(mx, -1, sizeof(mx));
memset(my, -1, sizeof(my));
while(bfs())
{
memset(used, 0, sizeof(used));
for(int i = 1; i <= amount; i++)
{
if(mx[id[i]] == -1 && dfs(id[i]))ans++;
}
}
printf("Case %d: %d\n", t, n - ans);
}
return 0;
}