Lightoj1356

题目链接:https://vjudge.net/problem/LightOJ-1356

题目大意:

  T个 test case,每个 test case 给出一个 N 个数的集合。请找出一个最大的子集,使得子集中的任何一个数除以子集中的任意的另一个数所得到的数不是质数。

解题思路:

  先用素数筛找出 1 到 500000 的所有质数。

  在输入一个集合的时候,我们顺便记录下输入的这个数在输入数组中的位置,找出它的所有质因数,记录下质因数的总个数,用一个vector记录下所有 “不同的” 质因数。

  遍历输入数组中的每一个数,对于每个数,遍历其所有 “不同的” 质因数,如果找到这样的一个质因数:该数除以这个质因数能得到输入数组中的另一个数,那么将这两个数连边。

  将由上述的连边操作得到的图中的点分成两类:质因数总个数为奇数的点和质因数总个数为偶数的点(这个划分有点隐晦,我多说两句:其实,对于连边的两个数,二者各自的所有质因数其实就只有一个质数的差别,其中一个数的所有质因数中有这个质数,但另一个数没有,其他的质因数都相同;所以,他们质因数的总个数相差 1,故其中一个为奇数,一个为偶数),这样一来,这个图就变成一个二分图了。而答案其实就是求这个二分图的最大独立集。

  另:用匈牙利算法者,T!用 Hopcroft-Carp者方有可能AC。

AC代码:

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 
  7 using namespace std;
  8 const int inf=0x3f3f3f3f;
  9 
 10 bool prime[500003];
 11 int have[500003],num[40003];
 12 int prims[300003];
 13 
 14 vector<int> G[40003];
 15 int uN;
 16 int l[40003];
 17 int Mx[40003],My[40003];
 18 int dx[40003],dy[40003];
 19 int dis;
 20 bool used[40003];
 21 bool SearchP(){
 22     queue<int>Q;
 23     dis=inf;
 24     memset(dx,-1,sizeof(dx));
 25     memset(dy,-1,sizeof(dy));
 26     for(int i=0;i<uN;i++){
 27         if(Mx[l[i]]==-1){
 28             Q.push(l[i]);
 29             dx[l[i]]=0;
 30         }
 31     }
 32     while(!Q.empty()){
 33         int u=Q.front();
 34         Q.pop();
 35         if(dx[u]>dis)   break;
 36         int sz=G[u].size();
 37         for(int i=0;i<sz;i++){
 38             int v=G[u][i];
 39             if(dy[v]==-1){
 40                 dy[v]=dx[u]+1;
 41                 if(My[v]==-1) dis=dy[v];
 42                 else{
 43                     dx[My[v]]=dy[v]+1;
 44                     Q.push(My[v]);
 45                 }
 46             }
 47         }
 48     }
 49     return dis!=inf;
 50 }
 51 bool DFS(int u){
 52     int sz=G[u].size();
 53     for(int i=0;i<sz;i++){
 54         int v=G[u][i];
 55         if(!used[v]&&dy[v]==dx[u]+1){
 56             used[v]=true;
 57             if(My[v]!=-1&&dy[v]==dis)   continue;
 58             if(My[v]==-1||DFS(My[v])){
 59                 My[v]=u;
 60                 Mx[u]=v;
 61                 return true;
 62             }
 63         }
 64     }
 65     return false;
 66 }
 67 int MaxMatch(){
 68     int res=0;
 69     memset(Mx,-1,sizeof(Mx));
 70     memset(My,-1,sizeof(My));
 71     while(SearchP()){
 72         memset(used,false,sizeof(used));
 73         for(int i=0;i<uN;i++){
 74             if(Mx[l[i]]==-1&&DFS(l[i]))   res++;
 75         }
 76     }
 77     return res;
 78 }
 79 void init(){
 80     memset(prime,true,sizeof(prime));
 81     prime[0]=prime[1]=false;
 82     int cnt=0;
 83     for(int i=2;i<=500000;i++){
 84         if(prime[i]){
 85             prims[cnt++]=i;
 86             for(int j=2*i;j<=500000;j+=i)
 87                 prime[j]=false;
 88         }
 89     }
 90 }
 91 int zhis[40003];
 92 vector<int> zhiyinshu[40003];
 93 int main(){
 94     init();
 95     int T,N;
 96     scanf("%d",&T);
 97     for(int t=1;t<=T;t++){
 98         scanf("%d",&N);
 99         memset(have,0,sizeof(have));
100         memset(zhis,0,sizeof(zhis));
101         for(int i=1;i<=N;i++){
102             G[i].clear();
103             zhiyinshu[i].clear();
104             scanf("%d",&num[i]);
105             have[num[i]]=i;
106             int tmp=num[i];
107             for(int j=0;;j++){
108                 if(prime[tmp]){
109                     zhiyinshu[i].push_back(tmp);
110                     zhis[i]++;
111                     break;
112                 }
113                 if(tmp%prims[j]==0){
114                     tmp/=prims[j];
115                     zhiyinshu[i].push_back(prims[j]);
116                     zhis[i]++;
117                     while(tmp%prims[j]==0){
118                         tmp/=prims[j];
119                         zhis[i]++;
120                     }
121                 }
122                 if(tmp<prims[j])    break;
123             }
124         }
125         for(int i=1;i<=N;i++){
126             for(int j=0;j<zhiyinshu[i].size();j++){
127                 if(have[num[i]/zhiyinshu[i][j]]){
128                     int u=have[num[i]/zhiyinshu[i][j]];
129                     G[i].push_back(u);
130                     G[u].push_back(i);
131                 }
132             }
133         }
134 
135         uN=0;
136         for(int i=1;i<=N;i++){
137             if(zhis[i]%2==1){
138                 l[uN++]=i;
139             }
140         }
141         printf("Case %d: %d\n",t,N-MaxMatch());
142     }
143     return 0;
144 }

 

posted @ 2017-09-21 01:08  Blogggggg  阅读(285)  评论(0编辑  收藏  举报