light_oj 1356 素数独立集,二分图最大独立集
light_oj 1356 素数独立集,二分图最大独立集
Description
A set of integers is called prime independent if none of its member is a prime multiple of another member. An integera 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
题意:定义素数独立集为一个整数集(不一定全是素数),该整数集合中的任意两个a和b,不存在a=b*prime的情况(prime为素数),视为该情况为"冲突",独立集即不存在冲突的集合。
思路:首先看到独立集就应该想到二分图,既然是二分图,每个数为一个结点,哪些是U哪些是V呢?自然而然地每个数a进行素因数分解,素因子个数为奇数的和素因子个数为偶数的才有可能有a=b*prime的情况,才有可能出现冲突,而奇数个素因子的整数和奇数个素因子的整数是不冲突的,偶数也是如此,按照奇偶分为UV两个子图,冲突连边,求最大独立集即可。
这题之所以卡了这么久,原因就是之前对二分图建图不太熟悉,为了降低复杂度以及适应模版(模版下标从0->uN-1),二分图目前学到两种方式建图,一是类似U和V不重复,即U从0->uN-1,V从uN->N-1;另一种就是拆点了,U从0->uN-1,V从0->vN-1,虽然不知道第二种的正确性如何验证,目前会用就行,以后再纠结。
这题显然第二种方便些,这里不以原整数或原数组下标直接表示结点也是为了适应模版,为了方便清晰的表示U和V,我又另开了两个数组以及两个映射到下标的数组,映射到下标的数组同时也起到判断整数是否存在的作用即提供了一部分vis数组的功能。
思路清晰了,这题秒A!也不是很难。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define PII pair<int,int> #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",s) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)v.size() using namespace std; const int maxn=500100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int a[maxn/10],id[maxn],n; int U[maxn/10],idU[maxn],uN; int V[maxn/10],idV[maxn],vN; bool isprime[maxn]; vector<int> prime; vector<int> G[maxn]; int Mx[maxn/10],My[maxn/10]; int dx[maxn/10],dy[maxn/10],dis; bool vis[maxn]; vector<int> v; set<int> s; bool searchP() { queue<int> q; dis=INF; MS1(dx);MS1(dy); REP(i,0,uN-1){ if(Mx[i]==-1){ q.push(i); dx[i]=0; } } while(!q.empty()){ int u=q.front(); q.pop(); if(dx[u]>dis) break; REP(i,0,(int)SZ(G[u])-1){ int v=G[u][i]; if(dy[v]==-1){ dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else{ dx[My[v]]=dy[v]+1; q.push(My[v]); } } } } return dis!=INF; } bool dfs(int u) { REP(i,0,SZ(G[u])-1){ int v=G[u][i]; if(!vis[v]&&dy[v]==dx[u]+1){ vis[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||dfs(My[v])){ My[v]=u; Mx[u]=v; return true; } } } return false; } int MaxMatch() { int res=0; MS1(Mx);MS1(My); while(searchP()){ MS0(vis); REP(i,0,uN-1){ if(Mx[i]==-1&&dfs(i)) res++; } } return res; } void getPrime() { MS(isprime,1); isprime[1]=0; REP(i,2,maxn-1){ if(!isprime[i]) continue; REPP(j,i*2,maxn-1,i) isprime[j]=0; } REP(i,1,maxn-1) if(isprime[i]) prime.PB(i); } int main() { getPrime(); DRI(T); REP(casen,1,T){ MS1(id); MS1(idU); MS1(idV); uN=vN=0; RI(n); REP(i,0,n) G[i].clear(); REP(i,0,n-1) RI(a[i]); sort(a,a+n); REP(i,0,n-1) id[a[i]]=i; REP(i,0,n-1){ int t=a[i]; v.clear(); s.clear(); REP(j,0,SZ(prime)-1){ int p=prime[j]; if(p*p>t) break; while(t%p==0) t/=p,v.PB(p),s.insert(p); } if(t>1) v.PB(t),s.insert(t); if(SZ(v)&1){ int u=idU[a[i]]=uN; U[uN++]=a[i]; for(set<int>::iterator j=s.begin();j!=s.end();j++){ int x=a[i]/(*j); if(idV[x]!=-1) G[u].PB(idV[x]); } } else{ int v=idV[a[i]]=vN; V[vN++]=a[i]; for(set<int>::iterator j=s.begin();j!=s.end();j++){ int x=a[i]/(*j); if(idU[x]!=-1) G[idU[x]].PB(v); } } } printf("Case %d: %d\n",casen,n-MaxMatch()); } return 0; }