HihoCoder 1158 : 质数相关 (最大独立集)

质数相关

时间限制:2000ms
单点时限:1000ms
内存限制:256MB

描述

两个数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
 
即是求最大独立集,不是男女类型,泛化最后除2即可。
 
预处理,先素数筛选
 
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1010;
const int maxm=500010;
int link[maxn],used[maxn],a[maxn];
vector<int>G[maxn];
bool p[maxm];
void prime()
{
    for(int i=2;i<=500000;i++){
        if(!p[i]) {
               for(int j=i+i;j<=500000;j+=i)
                    p[j]=true;
        }
    }
}
bool find(int u)
{
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(used[v]) continue;
        used[v]=1;
        if(!link[v]||find(link[v])){
            link[v]=u;
            return true;
        }
    }
    return false;
}
int main()
{
    int i,j,n,T,ans=0,Case=0;
    prime();
    scanf("%d",&T);
    while(T--){
        ans=0;
        memset(link,0,sizeof(link));
        scanf("%d",&n);
        for(i=1;i<=n;i++) G[i].clear();
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        for(i=1;i<=n;i++)
         for(j=i+1;j<=n;j++){
                int tmp=a[j]/a[i];
                if(tmp*a[i]==a[j]&&!p[tmp]){
                    G[i].push_back(j);
                    G[j].push_back(i);
                }
         }
        for(i=1;i<=n;i++){
             memset(used,0,sizeof(used));
             if(find(i)) ans++;
        }
        printf("Case #%d: ",++Case);
        printf("%d
",n-ans/2);
    }
    return 0;
}