该题是求二分图, 最大独立集。
最大独立集合 == 节点数 — 最小点覆盖(最小点覆盖== 最大匹配)。
所以就要构造 出二分图:
通过 某个数的质因子乘积个数 划分二分图。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 500010;
const int MAXN = 40010;
int arr[MAXN];//原数组
int id[maxn];// id数组, id为0表示该数不存在
int n;
vector<int>G[MAXN];// 存图
void input();
void ID();
void process();
int link[MAXN];//连接数组, y 与link[y]相连
bool mark[MAXN];//标记数组 标记y是否可以连接
int dfs(int x)
{
for(int i = 0; i < (int)G[x].size(); i++)
{
int y = G[x][i];
if(mark[y] == 0)
{
mark[y] = 1;
if(!link[y]||dfs(link[y]))
{
link[y] = x;
return 1;
}
}
}
return 0;
}
int hunger()
{
int ret = 0;
memset(link, 0, sizeof(link));
for(int i = 1; i <= n; i++)
{
memset(mark,0,sizeof(mark));
ret+=dfs(i);
}
return ret;
}
void init()
{
for(int i = 1; i <= n; i++)
{
G[i].clear();
}
memset(id, 0,sizeof(id));
}
int factor[1000];
int main()
{
int T;
scanf("%d", &T);
int cnt2 = 0;
while(T--)
{
input();
init();//初始化
ID();//id
printf("Case %d: ", ++cnt2);
int ans = 0;
for(int i = 1; i <= n; i++)
{
int cnt = 0, sum = 0;//质因子的个数, 和质因子总数
int x = arr[i];
for(int j = 2; x>1&&j <= sqrt(x); j++)
{
if(x%j == 0)
{
factor[cnt++] = j;
while(x%j == 0)
{
x/=j;
sum++;
}
}
}
if(x >1)
{
factor[cnt++] = x;
sum++;
}
for(int j = 0; j < cnt; j++)
{
int k = factor[j];
int id2 = id[arr[i]/k];
if(id2 == 0)continue;
//通过 质因子乘积个数 划分 二分图, 奇数为x 有数为y
if(sum&1)
{
G[i].push_back(id2);
}
else
{
G[id2].push_back(i);
}
}
}
ans = hunger();//二分图匹配
printf("%d\n",n- ans);
}
return 0;
}
void ID()
{
for(int i = 1; i <= n; i++)
{
id[arr[i]] = i;
}
}
void input()// 输入函数
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &arr[i]);
}
}