LightOJ 1356 Prime Independence( Hopcroft–Karp Bipartite算法)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1356

题意:给定n个数,找到一个最大的集合使得集合中不存在任意两个数a和b,使得b=a*k(k为素数)。

思路:对于每个数x定义f(x),若x=p1^e1*………pt^et。f(x)=e1+e2+……et。那么可知,若两个数a和b满足b=a*k(k为素数),则f(a)和f(b)的奇偶性必然不同。据此建立二分图,设最大匹配为x,则 答案为n-x。

#include <iostream>

#include <cstdio>

#include <string.h>

#define max(x,y) ((x)>(y)?(x):(y))

#define i64 long long

#define u32 unsigned int

using namespace std;

 

 

int C,Num=0;

 

 

const i64 MAX=500005;

bool tag[MAX];

int prime[MAX/10],cnt;

int p[MAX];

 

 

void init()

{

    int i,j;

    for(i=2;i<710;i++) if(!tag[i])

    {

        prime[cnt++]=i;

        for(j=i+i;j<710;j+=i) tag[j]=1;

    }

    for(i=2;i<MAX;i++)

    {

        for(j=0;j<cnt&&prime[j]<i;j++) if(i%prime[j]==0)

        {

            p[i]=p[i/prime[j]]+1;

            break;

        }

        if(!p[i]) p[i]++;

    }

}

 

struct node

{

    int v,next;

};

 

const int M=40005;

int a[M],b[MAX],n;

node edges[MAX];

int head[M],e;

 

 

void Add(int u,int v)

{

    edges[e].v=v;

    edges[e].next=head[u];

    head[u]=e++;

}

 

int match[M],opt[M],dx[M],dy[M],Q[M];

 

int BFS()

{

    int front=0,tail=0,flag=0,i,j,u,v;

    for(i=1;i<=n;i++) dx[i]=dy[i]=0;

    for(i=1;i<=n;i++) if(!opt[i]) Q[tail++]=i,dx[i]=1;

    while(front<tail)

    {

        u=Q[front++];

        for(i=head[u];i!=-1;i=edges[i].next)

        {

            v=edges[i].v;

            if(dy[v]) continue;

            dy[v]=dx[u]+1;

            if(!match[v]) flag=1;

            else

            {

                Q[tail++]=match[v];

                dx[match[v]]=dy[v]+1;

            }

        }

    }

    return flag;

}

 

int DFS(int u)

{

    int i,v,t;

    for(i=head[u];i!=-1;i=edges[i].next)

    {

        v=edges[i].v;

        if(dy[v]!=dx[u]+1) continue;

        dy[v]=0;

        t=match[v];

        match[v]=u;opt[u]=v;opt[t]=0;

        if(!t||DFS(t))return 1;

        opt[u]=0;match[v]=t;opt[t]=v;

    }

    return 0;

}

 

int MaxMatch()

{

    int i,ans=0;

    for(i=1;i<=n;i++) opt[i]=match[i]=0;

    while(BFS())

    {

        for(i=1;i<=n;i++) if(!opt[i]&&DFS(i)) ans++;

    }

    return ans;

}

 

 

inline void read(int &x)

{

    char c;

    for(c=getchar();!(c>='0'&&c<='9');c=getchar());

    x=c-'0';

    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';

}

 

int main()

{

    init();

    for(scanf("%d",&C);C--;)

    {

        read(n);

        int i,j,k,t;

        memset(b,0,sizeof(b));

        for(i=1;i<=n;i++)

        {

            read(a[i]);

            b[a[i]]=i;

        }

        for(i=1;i<=n;i++) head[i]=-1;

        e=0;

        int pr[25],prNum;

        for(i=1;i<=n;i++)

        {

            t=a[i];

            prNum=0;

            for(j=0;j<cnt&&prime[j]*prime[j]<=t;j++) if(t%prime[j]==0)

            {

                pr[++prNum]=prime[j];

                while(t%prime[j]==0) t/=prime[j];

            }

            if(t>1) pr[++prNum]=t;

            for(j=1;j<=prNum;j++)

            {

                k=a[i]/pr[j];

                if(!b[k]) continue;

                if(p[a[i]]&1) Add(b[a[i]],b[k]);

                else Add(b[k],b[a[i]]);

 

            }

        }

        printf("Case %d: %d\n",++Num,n-MaxMatch());

    }

    return 0;

}

 

  

 

你可能感兴趣的:(Prim)