hihocoder 1158 質數相關(二分圖匹配 最大獨立集)

bigbigship發表於2015-09-21

題目連結:傳送門 

題意:

    給定你一個為n的集合選定一個最大的子集使得不存在 ai*p=aj的情況,p為一個素數。

分析:

    對於所有的ai*p=aj的情況建圖,求出這個二分圖的最大匹配,然後n-最大匹配數/2即可。

程式碼如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 1010;

const int N = 500000+10;

int a[maxn];

int prime[N],cnt;

bool is[N];

void get_prime() {
    memset(is,0,sizeof(is));
    cnt = 0;
    is[1]=1;
    for(int i=2; i<N; i++) {
        if(!is[i]) {
            prime[cnt++]=i;
            for(int j=i+i; j<N; j+=i)
                is[j]=1;
        }
    }
}

bool vis[maxn];
int link[maxn],head[maxn*2];
int ip;

struct nod {
    int to;
    int next;
} edg[maxn*maxn];

void init1() {
    ip=0;
    memset(head,-1,sizeof(head));
}

void add(int u,int v) {
    edg[ip].to=v;
    edg[ip].next=head[u];
    head[u]=ip++;
}

bool dfs(int u) {
    for(int i=head[u]; i!=-1; i=edg[i].next) {
        int v=edg[i].to;
        if(!vis[v]) {
            vis[v]=1;
            if(link[v]==-1||dfs(link[v])) {
                link[v]=u;
                return true;
            }
        }
    }
    return false;
}

int max_match(int n) {
    int ans = 0;
    memset(link,-1,sizeof(link));
    for(int i=1; i<=n; i++) {
        memset(vis,0,sizeof(vis));
        if(dfs(i)) ans++;
    }
    return ans;
}


int main() {
    get_prime();
    int t,n,cas=1;
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d",a+i);
        }
        init1();
        sort(a+1,a+1+n);
        for(int i=1; i<=n; i++) {
            for(int j=i+1; j<=n; j++) {
                if(a[j]%a[i]==0&&!is[a[j]/a[i]]) {
                    add(j,i);
                    add(i,j);
                }
            }
        }
        int mmax = max_match(n);
        printf("Case #%d: %d\n",cas++,n-mmax/2);
    }
    return 0;
}
/****
3
5
2 4 8 16 32
5
2 3 4 6 9
3
1 2 3
***/



相關文章