Lightoj-1356 Prime Independence(质因子分解)(Hopcroft-Karp优化的最大匹配)

时间:2021-01-17 18:41:25

题意:

找出一个集合中的最大独立集,任意两数字之间不能是素数倍数的关系。

思路:

最大独立集,必然是二分图。

最大数字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+;
int n,m,sum,res,flag;
bool mark[*N];
int pri[N],cnt;
void SP()
{
cnt=;
memset(mark,true,sizeof(mark));
mark[]=mark[]=false;
for(int i=; i<*N; i++)
{
if(mark[i])
pri[cnt++]=i;
for (int j=; (j<cnt)&&(i*pri[j]<*N); j++)
{
mark[i*pri[j]]=false;
if (i%pri[j]==)
break;
}
}
}
int pos[*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=;
memset(pos,,sizeof(pos));
memset(f,-,sizeof(f));
memset(vm,-,sizeof(vm));
memset(um,-,sizeof(um));
for(int i=; 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,-,sizeof(dx));
memset(dy,-,sizeof(dy));
for(int i=; i<=sum; i++)
if(um[i]==-)
{
q.push(i);
dx[i]=;
}
while(!q.empty())
{
int u=q.front();
q.pop();
if(dx[u]>dis) break;
for(int i=; i<g[u].size(); i++)
{
int v = g[u][i];
if(dy[v]==-)
{
dy[v]=dx[u]+;
if(vm[v]==-) dis=dy[v];
else
{
dx[vm[v]]=dy[v]+;
q.push(vm[v]);
}
}
}
}
return dis!=inf;
}
bool dfs(int u)
{
for(int i=; i<g[u].size(); i++)
{
int v = g[u][i];
if(!vis[v]&&dy[v]==dx[u]+)
{
vis[v]=;
if(vm[v]!=-&&dy[v]==dis) continue;
if(vm[v]==-||dfs(vm[v]))
{
vm[v]=u;
um[u]=v;
return ;
}
}
}
return ;
}
int maxMatch()
{
int res=;
while(searchP())
{
memset(vis,,sizeof(vis));
for(int i=; i<=sum; i++)
if(um[i]==-&&dfs(i)) res++;
}
return res;
}
int tmp[N],now,all;
void solve(int t,int tot)
{
now = all = ;
int tt=t;
for(int i=; i<cnt&&pri[i]*pri[i]<=tt; i++)
{
if(tt%pri[i]==)
tmp[now++] = pri[i];
while(tt%pri[i]==)
tt/=pri[i],all++;
}
if(tt>)tmp[now++] = tt, all++;
f[tot]=&all;
if(f[tot])n++;
else m++;
for(int i=; 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=;
while(T--)
{
scanf("%d",&sum);
init();
for(i=; i<=sum; i++)
scanf("%d",&num[i]);
for(i=; i<=sum; i++)
pos[num[i]] = i;
for(i=; i<=sum; i++)
solve(num[i],i);
printf("Case %d: %d\n",++cas,sum-maxMatch());
}
return ;
}