描述
两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。
输入
第一行为一个数T,为数据组数。之后每组数据包含两行。
第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。
输出
对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。
数据范围
1 ≤ T ≤ 20
集合S内的数两两不同且范围在1到500000之间。
小数据
1 ≤ N ≤ 15
大数据
1 ≤ N ≤ 1000
3 5 2 4 8 16 32 5 2 3 4 6 9 3 1 2 3
样例输出
Case #1: 3 Case #2: 3 Case #3: 2
这道题就是求一个最大独立集,所谓最大独立集就是在一个集合里面,去任意两个元素,这两个元素不属于同一个其他子集合;而二分图最大匹配最适合求这个;
思路:
首先我们先用素数筛选将素数筛选出来,在将符合条件的a%b==0的两个数建边,注意这里我们要将一个点拆分成两个点
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#define ll long long
#define nn 1009
#define inff -0x3fffffff
using namespace std;
bool tu[1009][1009];
bool vis[nn];
ll pre[nn];
ll n;
ll prime_len;
ll primes[100000];
bool gash[100000];
ll cmp(ll aa1,ll aa2)
{
return aa1<aa2;
}
/素数筛选
void initPrimes(ll m)
{
ll i,j;
prime_len=0;
memset(gash,false,sizeof(gash));
for(i=2;i<=m;i++)
{
if(gash[i]==false)
{ primes[prime_len++]=i;
for(j=i+i;j<=m;j=j+i)
gash[j]=true;
}
}
}
/
/二分法查找两个数是否质素相关
ll BinSearch(ll Array[],ll SizeOfArray,ll key)
{
ll low=0,high=SizeOfArray-1;
ll mid;
while (low<=high)
{
mid = (low+high)/2;
if(key==Array[mid])
return 1;
if(key<Array[mid])
high=mid-1;
if(key>Array[mid])
low=mid+1;
}
return 0;
}
//
//二分匹配
bool dfs(ll id)
{
ll i;
for(i=0;i<n;i++)
{
if(tu[id][i]&&!vis[i])
{
vis[i]=true;
if(pre[i]==-1||dfs(pre[i]))
{
pre[i]=id;
return true;
}
}
}
return false;
}
ll slove()
{
ll i,re=0;
memset(pre,-1,sizeof(pre));
for(i=0;i<n;i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
re++;
}
return re;
}
int main()
{
ll i ,j;
ll t;
ll k;
ll a[100000];
initPrimes(60000);
while(scanf("%lld",&t)!=EOF)
{
ll b[10000];
ll cnt;
for(k=1;k<=t;k++)
{
cnt=0;
scanf("%lld",&n);
for(i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n,cmp);
memset(tu,false,sizeof(tu));
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(a[j]%a[i]==0)
{
ll bb=a[j]/a[i];
ll kk=BinSearch(primes,prime_len,bb);
if(kk==1)
{
tu[j][i]=true;
tu[i][j]=true; //将一个点拆成两个点
}
}
}
}
ll ff=slove();
printf("Case #%lld: %lld\n",k,(2*n-ff)/2);
}
}
}