hihoCoder 1158 质数相关

http://hihocoder.com/problemset/problem/1158

描述

两个数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


        二分图最大独立集(点数-最大匹配数)。这个题集合的划分很巧妙,一个数的素因子要么有奇数个,要么有偶数个,可以以此为依据划分两个集合。因为两个数要“质数相关”,必然素因子个数一奇一偶,只有这样才有可能连边。最大的质数无关集合,正好对应这个二分图的最大独立集,匈牙利算法跑一下就好了。

#include <bits/stdc++.h>
using namespace std;

const int maxn=1010;
#define ll long long

int n;
int s[maxn];
int s1[maxn],s2[maxn];
int size1,size2;

bool flag[502000];
int primes[41540];

//图相关 
int tote;
int head[maxn];
int to[maxn];
int pre[maxn];

void addedge(int u,int v){
	to[tote]=v;
	pre[tote]=head[u];
	head[u]=tote++;
	//to[tote]=u;
	//pre[tote]=head[v];
	//head[v]=tote++;
}

int match[maxn];
int used[maxn];
bool dfs(int u){
	for(int i=head[u];~i;i=pre[i]){
		
		int v=to[i];
		if(used[v])continue;
		used[v]=1;
		if(match[v]==-1||dfs(match[v])){
			match[v]=u;
			return 1;
		}
	}
	return 0;
}
//

//分为2部 
void div(){
	for(int i=1;i<=n;i++){
		int tmp=s[i];
		int cnt=0;
		for(int j=0;primes[j]<=tmp;j++){
			while(tmp%primes[j]==0){
				cnt++;
				tmp/=primes[j];
			}
		}
		if(cnt&1){
			s1[size1++]=s[i];
		}else{
			s2[size2++]=s[i];
		}
	}
}

void init(){
	size1=size2=0;
	tote=0;
	memset(head,-1,sizeof(head));
	memset(match,-1,sizeof(match));
}

int main(){
	//筛1~500000素数
	for(int i=2;i<=708;i++){
		for(int j=i+i;j<501264;j+=i){
			flag[j]=1;
		}
	}
	int cnt=0;
	for(int i=2;i<=500000;i++){
		if(!flag[i])primes[cnt++]=i;
	}
	
	int t;
	cin>>t;
	int cas=0;
	while(t--){
		init();
		cas++;
		
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>s[i];
		}
		div();
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				if(s1[i]%s2[j]==0&&!flag[s1[i]/s2[j]]){
					addedge(i,j);
				}else if(s2[j]%s1[i]==0&&!flag[s2[j]/s1[i]]){
					addedge(i,j);
				}
			}
		}
		
		//匈牙利算法
		int maxflow=0;
		for(int i=0;i<size1;i++){
			memset(used,0,sizeof(used));
			if(dfs(i))maxflow++;
		} 
		printf("Case #%d: %d\n",cas,n-maxflow);
	}
	return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值