light_oj 1356 素数独立集,二分图最大独立集

light_oj 1356 素数独立集,二分图最大独立集

B - Prime Independence
Time Limit:3000MS      Memory Limit:32768KB      64bit IO Format:%lld & %llu

Description

A set of integers is called prime independent if none of its member is a prime multiple of another member. An integera is said to be a prime multiple of b if,

a = b x k (where k is a prime [1])

So, 6 is a prime multiple of 2, but 8 is not. And for example, {2, 8, 17} is prime independent but {2, 8, 16} or {3, 6} are not.

Now, given a set of distinct positive integers, calculate the largest prime independent subset.

Input

Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with an integer N (1 ≤ N ≤ 40000) denoting the size of the set. Next line contains N integers separated by a single space. Each of these N integers are distinct and between 1 and 500000 inclusive.

Output

For each case, print the case number and the size of the largest prime independent subset.

Sample Input

3

5

2 4 8 16 32

5

2 3 4 6 9

3

1 2 3

Sample Output

Case 1: 3

Case 2: 3

Case 3: 2

题意:定义素数独立集为一个整数集(不一定全是素数),该整数集合中的任意两个a和b,不存在a=b*prime的情况(prime为素数),视为该情况为"冲突",独立集即不存在冲突的集合。

思路:首先看到独立集就应该想到二分图,既然是二分图,每个数为一个结点,哪些是U哪些是V呢?自然而然地每个数a进行素因数分解,素因子个数为奇数的和素因子个数为偶数的才有可能有a=b*prime的情况,才有可能出现冲突,而奇数个素因子的整数和奇数个素因子的整数是不冲突的,偶数也是如此,按照奇偶分为UV两个子图,冲突连边,求最大独立集即可。

这题之所以卡了这么久,原因就是之前对二分图建图不太熟悉,为了降低复杂度以及适应模版(模版下标从0->uN-1),二分图目前学到两种方式建图,一是类似U和V不重复,即U从0->uN-1,V从uN->N-1;另一种就是拆点了,U从0->uN-1,V从0->vN-1,虽然不知道第二种的正确性如何验证,目前会用就行,以后再纠结。

这题显然第二种方便些,这里不以原整数或原数组下标直接表示结点也是为了适应模版,为了方便清晰的表示U和V,我又另开了两个数组以及两个映射到下标的数组,映射到下标的数组同时也起到判断整数是否存在的作用即提供了一部分vis数组的功能。

思路清晰了,这题秒A!也不是很难。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<string>
#include<math.h>
#include<cctype>
#define ll long long
#define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t))
#define PII pair<int,int>
#define MP make_pair
#define PB push_back
#define RI(x) scanf("%d",&(x))
#define RII(x,y) scanf("%d%d",&(x),&(y))
#define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z))
#define DRI(x) int (x);scanf("%d",&(x))
#define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y))
#define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d",&(x),&(y),&(z))
#define RS(x) scanf("%s",s)
#define RSS(x,y) scanf("%s%s",x,y)
#define DRS(x) char x[maxn];scanf("%s",x)
#define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y)
#define MS0(a) memset((a),0,sizeof((a)))
#define MS1(a) memset((a),-1,sizeof((a)))
#define MS(a,b) memset((a),(b),sizeof((a)))
#define ALL(v) v.begin(),v.end()
#define SZ(v) (int)v.size()

using namespace std;

const int maxn=500100;
const int INF=(1<<29);
const double EPS=0.0000000001;
const double Pi=acos(-1.0);

int a[maxn/10],id[maxn],n;
int U[maxn/10],idU[maxn],uN;
int V[maxn/10],idV[maxn],vN;
bool isprime[maxn];
vector<int> prime;
vector<int> G[maxn];
int Mx[maxn/10],My[maxn/10];
int dx[maxn/10],dy[maxn/10],dis;
bool vis[maxn];
vector<int> v;
set<int> s;

bool searchP()
{
    queue<int> q;
    dis=INF;
    MS1(dx);MS1(dy);
    REP(i,0,uN-1){
        if(Mx[i]==-1){
            q.push(i);
            dx[i]=0;
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(dx[u]>dis) break;
        REP(i,0,(int)SZ(G[u])-1){
            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)
{
    REP(i,0,SZ(G[u])-1){
        int v=G[u][i];
        if(!vis[v]&&dy[v]==dx[u]+1){
            vis[v]=1;
            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;
    MS1(Mx);MS1(My);
    while(searchP()){
        MS0(vis);
        REP(i,0,uN-1){
            if(Mx[i]==-1&&dfs(i)) res++;
        }
    }
    return res;
}

void getPrime()
{
    MS(isprime,1);
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        REPP(j,i*2,maxn-1,i) isprime[j]=0;
    }
    REP(i,1,maxn-1) if(isprime[i]) prime.PB(i);
}

int main()
{
    getPrime();
    DRI(T);
    REP(casen,1,T){
        MS1(id);
        MS1(idU);
        MS1(idV);
        uN=vN=0;
        RI(n);
        REP(i,0,n) G[i].clear();
        REP(i,0,n-1) RI(a[i]);
        sort(a,a+n);
        REP(i,0,n-1) id[a[i]]=i;
        REP(i,0,n-1){
            int t=a[i];
            v.clear();
            s.clear();
            REP(j,0,SZ(prime)-1){
                int p=prime[j];
                if(p*p>t) break;
                while(t%p==0) t/=p,v.PB(p),s.insert(p);
            }
            if(t>1) v.PB(t),s.insert(t);
            if(SZ(v)&1){
                int u=idU[a[i]]=uN;
                U[uN++]=a[i];
                for(set<int>::iterator j=s.begin();j!=s.end();j++){
                    int x=a[i]/(*j);
                    if(idV[x]!=-1) G[u].PB(idV[x]);
                }
            }
            else{
                int v=idV[a[i]]=vN;
                V[vN++]=a[i];
                for(set<int>::iterator j=s.begin();j!=s.end();j++){
                    int x=a[i]/(*j);
                    if(idU[x]!=-1) G[idU[x]].PB(v);
                }
            }
        }
        printf("Case %d: %d\n",casen,n-MaxMatch());
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/--560/p/4582169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值