编程之美2015初赛A

题目3 : 质数相关

时间限制: 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

思路:

若两个数是质数相关的,则在两数之间连接一条无向边。根据质数相关的定义可发现,图中不可能存在奇数环,则可以通过黑白染色将集合分成两个部分,这两个部分的最大的一个,即为解。

//黑白染色
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

bool isprime[500000+5];
int t,n;
int a[20];
int p[20];
bool pcount[20][20];

bool cmp(int x, int y){
    return x < y;
}

void initg(){
    memset(isprime,false,sizeof(isprime));
    isprime[1] = isprime[0] = true;
    for(int i = 2; i <= 500000; i++){
        if(!isprime[i]){
            for(int j = i + i; j <= 500000; j += i)
                isprime[j] = true;
        }
    }
}

int qu[22];
int head,rear;
bool ispos[22];

int main(){
    initg();
    scanf("%d",&t);
    for(int item = 1; item <= t; item ++){
        scanf("%d",&n);
        for(int i = 0; i < n; i ++){
            scanf("%d",&a[i]);
        }

        sort(a,a+n,cmp);

        memset(pcount,false,sizeof(pcount));
        int tmp;
        for(int i = 0; i < n; i++){
            for(int j = i+1; j < n; j++){
                if(a[j] % a[i] == 0){
                    tmp = a[j] / a[i];
                    if(!isprime[tmp]){
                        pcount[i][j] = pcount[j][i] = true;
                    }
                }
            }
        }

        int total = 0;
        int ans_tmp;
        int total_ans;
        memset(ispos,false,sizeof(ispos));
        for(int i = 0; i < n; i++){
            if(!ispos[i]){
                head = rear = 0;
                memset(p,-1,sizeof(p));
                p[i] = 0;
                qu[rear++] = i;
                ispos[i] = true;

                while(head != rear){
                    int now = qu[head++];
                    for(int j = 0; j < n; j++){
                        if(pcount[now][j] && !ispos[j]){
                            qu[rear++] = j;
                            ispos[j] = true;
                            if(p[now] == 0) p[j] = 1;
                            else p[j] = 0;
                        }
                    }
                }

                total_ans = 0;
                ans_tmp = 0;
                for(int j = 0; j < n; j ++){
                    if(p[j] == 1) total_ans++;
                    if(p[j] == 0) ans_tmp ++;
                }

                if(total_ans > ans_tmp) total+=total_ans;
                else total+=ans_tmp;
            }
        }

        printf("Case #%d: %d\n",item,total);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值