Prime Independence LightOJ - 1356(质因子分解+最大点独立集)

8人阅读 评论(0) 收藏 举报
分类:

Prime Independence

LightOJ - 1356

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 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

Note

1.      An integer is said to be a prime if it's divisible by exactly two distinct integers. First few prime numbers are 2, 3, 5, 7, 11, 13, ...

2.      Dataset is huge, use faster I/O methods.

原博客地址 点击打开链接

限制:若a % b == 0 && a / b = k其中k是质数,则a和b不能同时存在于一个集合。

题意:给你n个数,让你求出满足上面限制的最大集合,输出元素个数。



思路:根据每个数质因子个数的奇偶性建立二分图,构好图。跑HK吧,匈牙利没敢写,甚至我HK都没敢用vector。


建图:不能二层for循环遍历建图,O(n*n)的建图复杂度承受不起。可以求出每个数a[i]的所有质因子p[],判断a[i] / p[]是否存在,然后根据奇偶性建图。这样建图时间复杂度最坏也就是O(n*10),然后加上HK,总时间复杂度

O(sqrt(n) * m + n * 10)。

code:

    #include <cstdio>  
    #include <cstring>  
    #include <algorithm>  
    #include <vector>  
    #include <queue>  
    #define MAXN 40000+10  
    #define MAXM 1000000+10  
    #define INF 0x3f3f3f3f  
    #define debug printf("1\n");  
    using namespace std;  
    struct Edge{  
        int to, next;  
    };  
    Edge edge[MAXM];  
    int head[MAXN], edgenum;  
    int P[500010], num[500010];//记录每个数是否是质数 记录每个数里面质因子的个数  
    int a[MAXN];  
    int id[MAXN];  
    int oddnum, evennum;  
    void getP()  
    {  
        memset(P, 0, sizeof(P));  
        for(int i = 2; i <= 500000; i++)  
        {  
            if(P[i]) continue;  
            for(int j = 2*i; j <= 500000; j+=i)  
                P[j] = 1;  
        }  
        P[1] = 1;  
    }  
    //vector<int> p[500000+10];  
    void getPsum()  
    {  
        for(int j = 1; j <= 500000; j++)  
        {  
            int cnt = 0;  
            int n = j;  
            for(int i = 2; i * i <= n; i++)  
            {  
                if(n % i == 0)  
                {  
                    while(n % i == 0)  
                    {  
                        cnt++;  
                        n /= i;  
                    }  
                }  
            }  
            if(n > 1)  
                cnt++;  
            num[j] = cnt;  
        }  
    }  
    void init(){  
        edgenum = 0;  
        memset(head, -1, sizeof(head));  
    }  
    void addEdge(int u, int v)  
    {  
        Edge E1 = {v, head[u]};  
        edge[edgenum] = E1;  
        head[u] = edgenum++;  
    }  
    int n;  
    int vis[500010];  
    int p[30], top;  
    void getprime(int n)  
    {  
        top = 0;  
        for(int i = 2; i * i <= n; i++)  
        {  
            if(n % i == 0)  
            {  
                p[top++] = i;  
                while(n % i == 0)  
                    n /= i;  
            }  
        }  
        if(n > 1)  
            p[top++] = n;  
    }  
    void getMap()  
    {  
        scanf("%d", &n);  
        oddnum = evennum = 0;  
        memset(vis, 0, sizeof(vis));  
        for(int i = 1; i <= n; i++)  
        {  
            scanf("%d", &a[i]);  
            vis[a[i]] = i;//标记该元素 已经出现过  
            if(num[a[i]] & 1)  
                id[i] = ++oddnum;  
            else  
                id[i] = ++evennum;  
        }  
        init();  
        for(int i = 1; i <= n; i++)  
        {  
            getprime(a[i]);//处理质因子  
            for(int j = 0; j < top; j++)  
            {  
                int goal = a[i] / p[j];  
                int index = vis[goal];  
                if(index)//存在  
                {  
                    if(num[a[i]] & 1 && num[a[index]] % 2 == 0)  
                        addEdge(id[i], id[index]);  
                    else if(num[a[i]] % 2 == 0 && num[a[index]] & 1)  
                        addEdge(id[index], id[i]);  
                }  
            }  
        }  
    }  
    bool used[MAXN];  
    int dx[MAXN], dy[MAXN];  
    int mx[MAXN], my[MAXN];  
    int DFS(int u)  
    {  
        for(int i = head[u]; i != -1; i = edge[i].next)  
        {  
            int v = edge[i].to;  
            if(!used[v] && dy[v] == dx[u] + 1)  
            {  
                used[v] = true;  
                if(my[v] == -1 || DFS(my[v]))  
                {  
                    my[v] = u; mx[u] = v;  
                    return 1;  
                }  
            }  
        }  
        return 0;  
    }  
    int kcase = 1;  
    void HK()  
    {  
        memset(mx, -1, sizeof(mx));  
        memset(my, -1, sizeof(my));  
        int ans = 0;  
        while(1)  
        {  
            bool flag = false;  
            memset(dx, 0, sizeof(dx));  
            memset(dy, 0, sizeof(dy));  
            queue<int> Q;  
            for(int i = 1; i <= oddnum; i++)  
                if(mx[i] == -1)  
                    Q.push(i);  
            while(!Q.empty())  
            {  
                int u = Q.front();  
                Q.pop();  
                for(int i = head[u]; i != -1; i = edge[i].next)  
                {  
                    int v = edge[i].to;  
                    if(!dy[v])  
                    {  
                        dy[v] = dx[u] + 1;  
                        if(my[v] == -1)  
                            flag = true;  
                        else  
                        {  
                            dx[my[v]] = dx[u] + 1;  
                            Q.push(my[v]);  
                        }  
                    }  
                }  
            }  
            if(!flag) break;  
            memset(used, false, sizeof(used));  
            for(int i = 1; i <= oddnum; i++)  
                if(mx[i] == -1)  
                    ans += DFS(i);  
        }  
        printf("Case %d: %d\n", kcase++, n - ans);  
    }  
    int main()  
    {  
        getP();  
        getPsum();  
        int t;  
        scanf("%d", &t);  
        while(t--)  
        {  
            getMap();  
            HK();  
        }  
        return 0;  
    }  


查看评论

LightOJ-1356 Prime Independence

题意: 找出一些数字的最大质独立集,就是集合能的所有数互相之间不会出现 a[i]==t*a[j] (t是质数) 的情况。 思路: 首先想最大独立集对于一般图是NP问题,通常只有求二分图最大独...
  • kopyh
  • kopyh
  • 2015年09月28日 23:47
  • 860

lightoj 1356 - Prime Independence 【质因子分解 奇偶构图 + HK优化】

1356 - Prime Independence PDF (English) Statistics Forum Time Limit: 3 second(s) Memory...
  • chenzhenyu123456
  • chenzhenyu123456
  • 2015年10月25日 21:32
  • 793

LightOJ 1356 Prime Independence (素数 二分图)

Prime Independence Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Su...
  • u010228612
  • u010228612
  • 2015年06月01日 23:38
  • 1076

【网络流第四弹】最大点权独立集 ——HDU 1565 方格取数(1)

题目:点击打开链接 网络流学习的下一步,最大点权独立集。多和最小点权覆盖集放到一起使用。分别求图中不相邻的点权最大/或者边中至少有一点在集合中,求最小总权值的问题。 公式: 最大点权独立集=总权...
  • mig_davidli
  • mig_davidli
  • 2013年04月30日 21:29
  • 2043

LightOJ 1356 Prime Independence

题意:给出n个数,求最大集合,这个集合要求满足:任意两个元素a,b,当a % b == 0 && a / b == k,若k是质数,则a,b不能同时在这个集合内 题解:最大独立子集问题,建一个二分图...
  • zztrhxnss
  • zztrhxnss
  • 2018年01月02日 20:03
  • 47

二分图的最大点权独立集和最小点权覆盖集

一个定理:二分图的最小点权覆盖集对应最大点权独立集          最小点权覆盖集的建图方法:                 1、增加源点 s,连接 s 到 x 集合中所有点,边权是相应点...
  • zhjchengfeng5
  • zhjchengfeng5
  • 2012年09月08日 18:13
  • 836

树的最小支配集,最小点覆盖与最大独立集

首先看一下三者的定义: 定义1 对于图G=(V,E)来说, 最小支配集 指的是从V中取尽量少的点组成一个集合,使得对于V中剩余的点都与取出来的点有边相连。也就是说,设V‘是图G的一个支配集,则对于图...
  • M_AXSSI
  • M_AXSSI
  • 2016年03月06日 15:15
  • 1305

最小点权覆盖=最大点权独立集

根据最大点权独立集的定义,如果(x,y) in E,则x和y不能都在独立集V'中,即 (co- 表示补集,真是不幸,没有公式用)     !(x in V' && y in V')    ! x...
  • pvpishard
  • pvpishard
  • 2011年08月28日 22:32
  • 851

HDU 1569 - 方格取数(2) 二分图最大点权独立集(构图最大流解)

题意:                       给你一个m*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并...
  • kk303
  • kk303
  • 2013年08月24日 18:31
  • 1687

【BZOJ 1475】方格取数 最大点权独立集

首先可以很明确的是原图一定是二分图(i+j为奇数的和偶数的格子没有边),先摆出结论:最大独立点集=sum-最小割 原因:我们这样建图,s向所有i+j为奇数的格子连边,点权是格子上面的数大小,i+j为...
  • pbihao
  • pbihao
  • 2017年01月17日 21:55
  • 122
    个人资料
    持之以恒
    等级:
    访问量: 3万+
    积分: 3929
    排名: 9768
    文章存档
    最新评论