题意:
给出 n n n个数,在这 n n n个数组成的集合中,两两之间相除不出现素数。问这个集合的最大值
SOL:
最大独立集=
n
n
n— 二分图的最大匹配值
对于两个数,如果他们的质因子数量是相等的,那么一定能在一个集合里面。所以,建立按照数字的奇偶性,建立二分图。用匈牙利算法求二分图的最大匹配值
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n;
int a[N], all[N], cnt[N];
int match[N];
int st[N];
vector<int> G[N];
vector<int> fac[N];
int uid;
void init()
{
for(int i = 1; i <= n; ++ i)
{
G[i].clear();
fac[i].clear();
cnt[i] = 0;
match[i] = -1;
}
}
bool find(int x)
{
for(int i = 0; i < G[x].size(); ++ i)
{
int j = G[x][i];
if(st[j] == uid) continue;
st[j] = uid;
if(match[j] == -1 || find(match[j])){
match[j] = x;
return true;
}
}
return false;
}
int main(){
int tt;
scanf("%d", &tt);
for(int T = 1; T <= tt; ++ T)
{
scanf("%d", &n);
// 初始化
init();
for(int i = 1; i <= n; ++ i)
{
scanf("%d", &a[i]);
all[a[i]] = i;
int x = a[i];
//筛质数,
for(int k = 2; k <= x / k; ++ k)
{
if(x % k == 0)
{
while( x % k == 0) x /= k, ++ cnt[i] ;
fac[i].push_back(k);
}
}
if(x > 1) fac[i].push_back(x), ++ cnt[i];
}
// 建二分图
for(int j = 1; j <= n; ++ j)
{
for(int k = 0; k < (int)fac[j].size(); ++ k)
{
int x = a[j] / fac[j][k];
if(all[x])
{
int tmp = all[x];
// 如果第j个数为奇数个素数,那么应该连j->tmp的边,偶数就反过来连
if(cnt[j] & 1) G[j].push_back(tmp);
else G[tmp].push_back(j);
}
}
}
// 匈牙利算法
int res = 0;
for(int i = 1; i <= n; ++i)
{
++ uid;
if(find(i)) ++ res;
all[a[i]] = 0;
}
printf("Case %d: %d\n", T, n - res);
}
return 0;
}