• LightOJ


    题意:有N个数的集合,其中选出若干个数组成一个子集,要求这个子集中的任意两个数a,b都不能通过a=k*b得到,其中k是一个素数。求这个子集最大的size。

    分析:集合中任意两数的关系是二者之间是否之差一个质因子,那么对于这种关系,本题要求的是N个点的最大独立集。|最大独立集| = 点数 - |二分图最大匹配|。

    想到这步之后,就是如何建图的问题。

    先预处理筛出一定范围内的素数。对于每个集合内的数a,检查其除去一个质因子后得到的数at是否在集合中出现,若出现则将a到at和at到a建边。

    因为是双向建边,所以得到的最大匹配数是两倍,除以2即可。

        #include<bits/stdc++.h>
        using namespace std;
        typedef long long LL;
        const int MAXN = 50010;
        const int MAXM = 1010*1010;
        const int INF = 0x3f3f3f3f;
        int N;
        struct Node{
            int x,y;
        }p[MAXN],it[MAXN];
        int v[MAXN];
    
        struct Edge{
            int v;
            int next;
        }edge[MAXM];
        
        int nx, ny;
        int cnt;
        int t;
        int dis;
    
        int first[MAXN];
        int xlink[MAXN], ylink[MAXN]; 
        /*xlink[i]表示左集合顶点所匹配的右集合顶点序号,ylink[i]表示右集合i顶点匹配到的左集合顶点序号。*/
        int dx[MAXN], dy[MAXN]; 
        /*dx[i]表示左集合i顶点的距离编号,dy[i]表示右集合i顶点的距离编号*/
        int vis[MAXN]; //寻找增广路的标记数组 
        void init(){
            cnt = 0;
            memset(first, -1, sizeof(first));
            memset(xlink, -1, sizeof(xlink));
            memset(ylink, -1, sizeof(ylink));
        }
        
        void AddEdge(int u, int v){
            edge[cnt].v = v;
            edge[cnt].next = first[u], first[u] = cnt++;
        }
        
        int bfs()
        {
            queue<int> q;
            dis = INF;
            memset(dx, -1, sizeof(dx));
            memset(dy, -1, sizeof(dy));
            for(int i = 1; i <= nx; i++){
                if(xlink[i] == -1){
                    q.push(i);
                    dx[i] = 0;
                }
            }
            while(!q.empty()){
                int u = q.front(); q.pop();
                if(dx[u] > dis) break;
                for(int e = first[u]; e != -1; e = edge[e].next){
                    int v = edge[e].v;
                    if(dy[v] == -1){
                        dy[v] = dx[u] + 1;
                        if(ylink[v] == -1) dis = dy[v];
                        else{
                            dx[ylink[v]] = dy[v]+1;
                            q.push(ylink[v]);
                        }
                    }
                }
            }
            return dis != INF;
        }
        
        int find(int u){
            for(int e = first[u]; e != -1; e = edge[e].next){
                int v = edge[e].v;
                if(!vis[v] && dy[v] == dx[u]+1){
                    vis[v] = 1;
                    if(ylink[v] != -1 && dy[v] == dis) continue;
                    if(ylink[v] == -1 || find(ylink[v])){
                        xlink[u] = v, ylink[v] = u;
                        return 1;
                    }
                }
            }
            return 0;
        }
        
        int MaxMatch()
        {
            int ans = 0;
            while(bfs()){
                memset(vis, 0, sizeof(vis));
                for(int i = 1; i <= nx; i++) 
                    if(xlink[i] == -1)  
                        ans += find(i);
            }
            return ans;
        }
    
        const int MAXV = 50005;
        int prime[MAXV];
        bool notprime[MAXV*10];
        void pre()
        {
            int up  = MAXV *10;
            memset(notprime,0,sizeof(notprime));
            notprime[0] = notprime[1] = true;
            memset(prime,0,sizeof(prime));
            for(int i=2;i<up;++i){
                if(!notprime[i]) prime[++prime[0]] = i;
                for(int j=1 ; j<=prime[0] && prime[j] <= up / i ;++j){
                    notprime[prime[j]*i] = true;
                    if(i%prime[j]==0) break;
                }
            }
        }
    
        int pos[MAXV*10];
        int num[MAXV];
        int fac[MAXV];
        bool jo[MAXV*10];
        void ADD(int num,int pt){
            int sum = 0,all=0;
            int tmp = num;
            for(int i=1;prime[i]*prime[i]<=tmp;i++){
                if(tmp%prime[i]==0){
                    fac[sum++] = prime[i];
                    while(tmp%prime[i]==0) tmp/=prime[i],all++;
                }
            }
            if(tmp>1) fac[sum++] = tmp,all++;
            for(int i=0;i<sum;++i){
                int x = num/fac[i];
                if(pos[x]){
                    AddEdge(pt,pos[x]);
                    AddEdge(pos[x],pt);
                }
            }
        }
    
        int main()
        {
            #ifndef ONLINE_JUDGE
                freopen("in.txt","r",stdin);
                freopen("out.txt","w",stdout);
            #endif
            pre();
            int T,cas=1; scanf("%d",&T);
            while(T--){
                int N; scanf("%d",&N);
                init();
                memset(pos,0,sizeof(pos));
                for(int i=1;i<=N;++i){
                    scanf("%d",&num[i]);
                    pos[num[i]] = i;
                }
                nx = ny =0;
                for(int i=1;i<=N;++i){
                    ADD(num[i],i);
                }
                nx = ny = N;
                int res= N - MaxMatch()/2;
                printf("Case %d: %d
    ",cas++,res);
            }
            return 0;
        }
    为了更好的明天
  • 相关阅读:
    js 带表情的评论输入框问题
    js 元素到指定的相对定位的父元素的距离
    html分享QQ,微信,显示分享图片,标题,简介
    网络空间安全0x01志向
    优秀的前端
    float探究
    转载的。。。
    判断有木有环
    居中(纯css方式)
    一个闭包的很好的考题, 闭包+递归
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9520421.html
Copyright © 2020-2023  润新知