Prime Independence
解题思路:
题目大意:
定义素数独立集为一个整数集(不一定全是素数),该整数集合中的任意两个a和b,如果存在a=b*prime的情况(prime为素数),则视为
该情况为"冲突"。独立集即不存在冲突的集合。
算法思想:
首先看到独立集就应该想到二分图,既然是二分图,每个数为一个结点,哪些是U哪些是V呢?自然而然地每个数num进行素因数分
解,素因子个数为奇数的和素因子个数为偶数的才有可能有a=b*prime的情况,才有可能出现冲突,而奇数个素因子的整数和奇数个
素因子的整数是不冲突的,偶数也是如此,按照奇偶分为UV两个子图,冲突连边,求最大独立集即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 40005;
int n;//顶点数
vector<int>prime;
int vis[500005];
int num[MAXN],p[2][500005];
vector<int> G[MAXN],v[MAXN];
int Mx[MAXN],My[MAXN];
int dx[MAXN],dy[MAXN];
int dis;
bool used[MAXN];//DFS中甬道的访问标记
void get_prime(){
memset(vis,0,sizeof(vis));
prime.clear();
for(int i = 2; i <= 500000; i++){
int tt = 500000/i;
for(int j = 2; j <= tt; j++)
vis[i*j] = 1;
}
for(int i = 2; i <= 500000; i++){
if(!vis[i])
prime.push_back(i);
}
}
void init(){
for(int i = 0; i <= n; i++){
G[i].clear();
v[i].clear();
}
}
bool SearchP(){
queue<int> q;
dis = INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i = 0 ; i < n; i++){
if(Mx[i] == -1){
q.push(i);
dx[i] = 0;
}
}
while(!q.empty()){
int u = q.front();
q.pop();
if(dx[u] > dis)
break;
int l = G[u].size();
for(int i = 0; i < l; i++){
int v = G[u][i];
if(dy[v] == -1){
dy[v] = dx[u] + 1;
if(My[v] == -1)
dis = dy[v];
else{
dx[My[v]] = dy[v] + 1;
q.push(My[v]);
}
}
}
}
return dis != INF;
}
bool dfs(int u){
int l = G[u].size();
for(int i = 0; i < l; i++){
int v = G[u][i];
if(!used[v] && dy[v] == dx[u] + 1){
used[v] = true;
if(My[v] != -1 && dy[v] == dis)
continue;
if(My[v] == -1 || dfs(My[v])){
My[v] = u;
Mx[u] = v;
return true;
}
}
}
return false;
}
int MaxMatch(){
int res = 0;
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
while(SearchP()){
memset(used, false, sizeof(used));
for(int i = 0; i < n; i++)
if(Mx[i] == -1 && dfs(i))
res++;
}
return res;
}
int main(){
get_prime();
int T,t = 1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
memset(p,0,sizeof(p));
for(int i = 1; i <= n; i++){
scanf("%d",&num[i]);
int t = num[i],cnt = 0;
for(int j = 0; prime[j]*prime[j] <= t; j++){
if(t % prime[j] == 0){
v[i].push_back(prime[j]);
while(t%prime[j] == 0)
cnt++,t /= prime[j];
}
}
if(t > 1){
v[i].push_back(t);
cnt++;
}
p[cnt&1][num[i]] = i;
}
for(int i = 1; i <= n; i++){
if(p[0][num[i]]){
for(int j = 0; j < v[i].size(); j++){
int tmp = num[i]/v[i][j];
if(!p[1][tmp])
continue;
G[i-1].push_back(p[1][tmp-1]);
}
}
else{
for(int j = 0; j < v[i].size(); j++){
int tmp = num[i]/v[i][j];
if(!p[0][tmp])
continue;
G[p[0][tmp]-1].push_back(i-1);
}
}
}
printf("Case %d: %d\n",t++,n-MaxMatch());
}
return 0;
}