题意
有n个数
求一个最大集合使得 集合内任意两数之商不为质数
思路
任何一个数都可以表示为质数的乘积
建立二分图将分成 奇数个组成的数 和偶数个质数相积的数
而求的最大集合就是
最大独立点集=点数量-最大匹配(仅在二分图中)
(概念就是 任意两点中没有相连的边)
用匈牙利算法求最大匹配
(实质是用dfs实现)
AC代码
#include<bits/stdc++.h>
#define endl "\n"
#define INF 0x3f3f3f3f3f3f3f
typedef long long ll;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
const double EI = exp(1.0);
const int N = 1e6 + 10;
const double eps = 1e-8;
using namespace std;
int a[N],all[N],cnt[N],match[N],st[N];
vector<int>G[N], fac[N];
int icase = 0;
int uid = 0;
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;
}
void solve()
{
ll ans = 0;
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
G[i].clear();
fac[i].clear();
cnt[i] = 0;
match[i] = -1;
}
for (int i = 1; i <= n; i++)
{
cin >> a[i];
all[a[i]] = i;
int x = a[i];
for (int k = 2; k * k <= x; ++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 < fac[j].size(); k++)
{
int x = a[j] / fac[j][k];
if (all[x])
{
int tmp = all[x];
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;
}
cout << "Case " << ++icase << ": "<<n-res << endl;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(); cout.tie(0);
int t; cin >> t; while (t--)
solve();
return 0;
}