Sweety

Practice makes perfect

导航

Prime Independence(质因子分解+二分图最大独立集)

Posted on 2016-05-13 20:40  蓝空  阅读(462)  评论(0编辑  收藏  举报

 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 integer a is said to be a prime multipleof 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


感觉超棒的一道题,值得一做。。。挺巧妙的。。。


找出一个集合中的最大独立集,任意两数字之间不能是素数倍数的关系。

思路:

最大独立集,必然是二分图。

最大数字50w,考虑对每个数质因子分解,然后枚举所有除去一个质因子后的数是否存在,存在则建边,考虑到能这样建边的数一定是质因子个数奇偶不同,所以相当于按奇偶区分建立了二分图,然后求二分图最大匹配,得到最大独立集就行了。



#pragma comment(linker, "/STACK:102400000,102400000"
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;

#define N 500010
#define M 40010

int a[M],b[N],num[M],factor[1000];
vector<int>mmap[M];
int n;
bool vis[M];
int linker[M];


bool dfs(int u)
{
    for(int i=0;i<mmap[u].size();i++)
    {
        if(!vis[mmap[u][i]])
        {
            vis[mmap[u][i]]=true;
            if(linker[ mmap[u][i] ]==-1||dfs(linker[ mmap[u][i] ]))
            {
                linker[mmap[u][i]]=u;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int u;
    int res=0;
    for(u=1;u<=n;u++)
    {
        memset(vis,false,sizeof(vis));
        if(dfs(u))
            res++;
    }
    return res;
}

void init()
{
    memset(num,0,sizeof(num));
    memset(b,0,sizeof(b));
    memset(linker,-1,sizeof(linker));
    for(int i=1;i<=n;i++)
        mmap[i].clear();
}
int main()
{
    int T,Case,t;

    scanf("%d",&T);
    Case=1;
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            b[ a[i] ]=i;  ///对节点哈希

        for(int i=1;i<=n;i++)
        {
            t = a[i];
            int cnt=0,sum=0; ///分解质因子 cnt质因子个数 sum为多少个质因子的积
            for(int j=2;t>1&&j<=sqrt(t) ;j++)
                if(t%j==0)
                {
                     factor[cnt++] = j;
                     while(t%j==0)
                        t/=j,sum++;
                }
            if(t>1) //t有可能是质数
                factor[cnt++]=t,sum++;
            num[i] = sum;

            for(int j=0;j<cnt;j++)
            {
                t = b[  a[i] / factor[j]  ];
                if(t==0) ///都是奇数或者偶数
                    continue;
                if((sum&1)) ///是奇数 作为x部
                    mmap[i].push_back(t);
                else   ///是偶数
                   mmap[t].push_back(i);
            }
        }
        printf("Case %d: %d\n",Case++,n-hungary());
    }
    return 0;
}


Hopcroft-Karp,数组有点乱。。。

#pragma comment(linker, "/STACK:102400000,102400000"
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;

#define N 500010
#define M 40010

int a[N],b[N],num[N],factor[1000];

vector<int>mmap[M];
int um[N],vm[N],n;
int dx[M],dy[M],dis;
bool vis[M];

bool searchP()
{
    queue<int>q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=1;i<=n;i++)
        if(um[i]==-1)
        {
            q.push(i);
            dx[i]=0;
        }
    while(!q.empty())
    {
        int u=q.front();q.pop();
        if(dx[u]>dis)  break;
        for(int i=0;i<mmap[u].size();i++)
        {
            int v = mmap[u][i];
            if(dy[v]==-1)
            {
                dy[v]=dx[u]+1;
                if(vm[v]==-1)  dis=dy[v];
                else
                {
                    dx[vm[v]]=dy[v]+1;
                    q.push(vm[v]);
                }
            }
        }
    }
    return dis!=INF;
}
bool dfs(int u)
{
    for(int i=0;i<mmap[u].size();i++)
    {
        int v = mmap[u][i];
        if(!vis[v]&&dy[v]==dx[u]+1)
        {
            vis[v]=1;
            if(vm[v]!=-1&&dy[v]==dis) continue;
            if(vm[v]==-1||dfs(vm[v]))
            {
                vm[v]=u;um[u]=v;
                return 1;
            }
        }
    }
    return 0;
}
int maxMatch()
{
    int res=0;
    memset(um,-1,sizeof(um));
    memset(vm,-1,sizeof(vm));
    while(searchP())
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
          if(um[i]==-1&&dfs(i))
            res++;
    }
    return res;
}

void init()
{
    memset(b,-1,sizeof(b));
    memset(num,0,sizeof(num));
    memset(vm,-1,sizeof(vm));
    memset(um,-1,sizeof(um));
    for(int i=0;i<=n;i++)
        mmap[i].clear();
}
int main()
{
    int k,kk,t,x,y,z;

    scanf("%d",&k);
    kk=0;
    while(k--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            b[ a[i] ]=i;

        for(int i=1;i<=n;i++)
        {
            t = a[i];
            int cnt=0,sum=0; ///分解质因子 cnt质因子个数 sum为多少个质因子的积
            for(int j=2;t>1&&j<=sqrt(t) ;j++)
                if(t%j==0)
                {
                     factor[cnt++] = j;
                     while(t%j==0)
                        t/=j,sum++;
                }
            if(t>1) //t有可能是质数
                factor[cnt++]=t,sum++;
            num[i] = sum;

            for(int j=0;j<cnt;j++)
            {
                t = b[  a[i] / factor[j]  ];
                if(  t==0 ) ///都是奇数或者偶数
                    continue;
                if((sum&1)) ///是奇数 作为x部
                    mmap[i].push_back(t);
                else   ///是偶数
                   mmap[t].push_back(i);
            }
        }
        printf("Case %d: %d\n",++kk,n-maxMatch());
    }
    return 0;
}