这个题唯一需要说的就是普通的匈牙利算法是O(nm)的,过不了
然后HK算法可以O(n^0.5m),这个算法可以每次找很多同样长度的最短增广路
分析见:http://www.hardbird.net/lightoj-1356-prime-independence%E6%9C%80%E5%A4%A7%E7%8B%AC%E7%AB%8B%E9%9B%86-hopcroft-carp%E7%AE%97%E6%B3%95/
#include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <queue> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; const int N=4e4+5; const int INF=0x3f3f3f3f; int prime[45000],cnt,T,n; int a[N],p[2][500005]; vector<int>fac[N],g[N]; void getprime(){ bool v[500005]; memset(v,0,sizeof(v)); for(int i=2;i*i<=500000;++i) if(!v[i]) for(int j=i*i;j<=500000;j+=i) v[j]=1; for(int i=2;i<=500000;++i) if(!v[i])prime[++cnt]=i; } int Mx[N],My[N],dx[N],dy[N],dis; bool used[N]; bool SearchP(){ queue<int>q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=1;i<=n;++i) if(Mx[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)continue; 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){ for(int i=0;i<g[u].size();++i){ int v=g[u][i]; if(!used[v]&&dy[v]==dx[u]+1){ used[v]=true; 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; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(SearchP()){ memset(used,0,sizeof(used)); for(int i=1;i<=n;++i) if(Mx[i]==-1&&dfs(i))++res; } return res; } int main() { getprime(); int cas=0; scanf("%d",&T); while(T--){ scanf("%d",&n); memset(p,-1,sizeof(p)); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); g[i].clear(); fac[i].clear(); int tot=0,t=a[i]; for(int j=1;prime[j]*prime[j]<=t;++j){ if(t%prime[j]==0){ fac[i].push_back(prime[j]); while(t%prime[j]==0)t/=prime[j],++tot; } } if(t>1)fac[i].push_back(t),++tot; p[tot&1][a[i]]=i; } for(int i=1;i<=n;++i){ if(p[0][a[i]]!=-1){ for(int j=0;j<fac[i].size();++j){ int tmp=a[i]/fac[i][j]; if(p[1][tmp]==-1)continue; g[i].push_back(p[1][tmp]); } } else{ for(int j=0;j<fac[i].size();++j){ int tmp=a[i]/fac[i][j]; if(p[0][tmp]==-1)continue; g[p[0][tmp]].push_back(i); } } } printf("Case %d: %d\n",++cas,n-MaxMatch()); } return 0; }