Lightoj-1356 Prime Independence(质因子分解)(Hopcroft-Karp优化的最大匹配)
题意:
找出一个集合中的最大独立集,任意两数字之间不能是素数倍数的关系。
思路:
最大独立集,必然是二分图。
最大数字50w,考虑对每个数质因子分解,然后枚举所有除去一个质因子后的数是否存在,存在则建边,考虑到能这样建边的数一定是质因子个数奇偶不同,所以相当于按奇偶区分建立了二分图,然后求二分图最大匹配,得到最大独立集就行了。
有一点这个题数据比较大,直接匈牙利炸了,要Hopcroft-Karp优化才能过。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <string> #include <stack> #include <queue> #include <vector> #include <map> #define inf 0x3f3f3f3f #define met(a,b) memset(a,b,sizeof a) #define pb push_back using namespace std; typedef long long ll; const int N = 5e4+10; int n,m,sum,res,flag; bool mark[10*N]; int pri[N],cnt; void SP() { cnt=0; memset(mark,true,sizeof(mark)); mark[0]=mark[1]=false; for(int i=2; i<10*N; i++) { if(mark[i]) pri[cnt++]=i; for (int j=0; (j<cnt)&&(i*pri[j]<10*N); j++) { mark[i*pri[j]]=false; if (i%pri[j]==0) break; } } } int pos[10*N],num[N]; int f[N]; int vm[N],um[N]; bool vis[N]; vector<int>g[N]; int dx[N],dy[N],dis; void init() { n=m=0; memset(pos,0,sizeof(pos)); memset(f,-1,sizeof(f)); memset(vm,-1,sizeof(vm)); memset(um,-1,sizeof(um)); for(int i=0; i<=sum; i++) g[i].clear(); } void inserts(int u, int v) { g[u].push_back(v); } bool searchP() { queue<int>q; dis=inf; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=1; i<=sum; i++) if(um[i]==-1) { q.push(i); dx[i]=0; } while(!q.empty()) { int u=q.front(); q.pop(); if(dx[u]>dis) break; for(int i=0; i<g[u].size(); i++) { int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(vm[v]==-1) dis=dy[v]; else { dx[vm[v]]=dy[v]+1; q.push(vm[v]); } } } } return dis!=inf; } bool dfs(int u) { for(int i=0; i<g[u].size(); i++) { int v = g[u][i]; if(!vis[v]&&dy[v]==dx[u]+1) { vis[v]=1; if(vm[v]!=-1&&dy[v]==dis) continue; if(vm[v]==-1||dfs(vm[v])) { vm[v]=u; um[u]=v; return 1; } } } return 0; } int maxMatch() { int res=0; while(searchP()) { memset(vis,0,sizeof(vis)); for(int i=1; i<=sum; i++) if(um[i]==-1&&dfs(i)) res++; } return res; } int tmp[N],now,all; void solve(int t,int tot) { now = all = 0; int tt=t; for(int i=0; i<cnt&&pri[i]*pri[i]<=tt; i++) { if(tt%pri[i]==0) tmp[now++] = pri[i]; while(tt%pri[i]==0) tt/=pri[i],all++; } if(tt>1)tmp[now++] = tt, all++; f[tot]=1&all; if(f[tot])n++; else m++; for(int i=0; i<now; i++) { int x=t/tmp[i]; if(pos[x]) { if(!f[tot])inserts(tot,pos[x]); else inserts(pos[x],tot); } } } int main() { int i,j,k,cas,T,t,x,y,z; SP(); scanf("%d",&T); cas=0; while(T--) { scanf("%d",&sum); init(); for(i=1; i<=sum; i++) scanf("%d",&num[i]); for(i=1; i<=sum; i++) pos[num[i]] = i; for(i=1; i<=sum; i++) solve(num[i],i); printf("Case %d: %d\n",++cas,sum-maxMatch()); } return 0; }