匈牙利算法
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
/*
求二分图的最大独立集
邻接表存图
匈牙利算法得到最大匹配(或最小顶点覆盖)hungary()
V-hungary()=最大独立集
*/
const int maxn=4e4+5;//点的最大值
const int maxm=5e5+5;
int n;
int a[maxn],b[maxm];
int factor[maxn];// 质因数
vector<int>G[maxn];//二分图
int linker[maxn];
bool used[maxn];
bool dfs(int u)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!used[v])
{
used[v]=true;
if(linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
}
return false;
}
//最大匹配
int hungary()
{
int res=0;
for(int u=1;u<=n;u++)
{
memset(used,0,sizeof(used));
if(dfs(u)) res++;
}
return res;
}
void init()
{
memset(linker,-1,sizeof(linker));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
{
G[i].clear();
}
}
int main()
{
int T,t;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
b[a[i]]=i;//对结点hash
}
for(int i=1;i<=n;i++)
{
t=a[i];
int cnt=0,sum=0;//分解质因子
//cnt为质因数个数,sum为质因数总数
for(int j=2;t>1&&j<=sqrt(t);j++)
{
if(t%j==0)
{
factor[cnt++]=j;
while(t%j==0)
{
t=t/j;
sum++;
}
}
}
if(t>1)//如果t为质数
{
factor[cnt++]=t;
sum++;
}
for(int j=0;j<cnt;j++)
{
t=b[ a[i]/factor[j] ];
if(t==0)//不存在对应关系
{
continue;
}
if(sum&1)共有奇数个质因子
{
G[i].push_back(t);
}
else共有偶数个质因子
{
G[t].push_back(i);
}
}
}
printf("Case %d: %d\n",kase,n-hungary());
}
return 0;
}
Hopcroft-Karp算法
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
/*
求二分图的最大独立集
邻接表存图
Hopcroft-Karp算法得到最大匹配(或最小顶点覆盖)MaxMatch()
V-MaxMatch()=最大独立集
*/
#define INF 0x3f3f3f3f
const int maxn=4e4+5;//点的最大值
const int maxm=5e5+5;
int n;
int a[maxn],b[maxm];
int factor[maxn];//质因数
vector<int>G[maxn];//二分图
int Mx[maxn],My[maxn];
int dx[maxn],dy[maxn];
int dis;
bool used[maxn];
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;
int sz=G[u].size();
for(int i=0;i<sz;i++)
{
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)
{
int sz=G[u].size();
for(int i=0;i<sz;i++)
{
int v=G[u][i];
if(!used[v]&&dy[v]==dx[u]+1)
{
used[v]=1;
if(My[v]!=-1&&dy[v]==dis) continue;
if(My[v]==-1||DFS(My[v]))
{
My[v]=u;
Mx[u]=v;
return 1;
}
}
}
return 0;
}
//最大匹配
int MaxMatch()
{
int res=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(SearchP())
{
memset(used,0,sizeof(used));
//点的编号[1,n]
for(int i=1;i<=n;i++)
{
if(Mx[i]==-1&&DFS(i))
{
res++;
}
}
}
return res;
}
void init()
{
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
{
G[i].clear();
}
}
int main()
{
int T,t;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
init();//清空
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
b[a[i]]=i;//对结点hash
}
for(int i=1;i<=n;i++)
{
t=a[i];
int cnt=0,sum=0;//分解质因子
//cnt为质因数个数,sum为质因数总数
for(int j=2;t>1&&j<=sqrt(t);j++)
{
if(t%j==0)
{
factor[cnt++]=j;
while(t%j==0)
{
t=t/j;
sum++;
}
}
}
if(t>1)//如果t为质数
{
factor[cnt++]=t;
sum++;
}
for(int j=0;j<cnt;j++)
{
t=b[ a[i]/factor[j] ];
//printf("t=%d a=%d factor=%d\n",t,a[i],factor[j]);
if(t==0)//不存在对应关系
{
continue;
}
if(sum&1)//共有奇数个质因子
{
G[i].push_back(t);
//printf("1 i=%d t=%d\n",i,t);
}
else//共有偶数个质因子
{
G[t].push_back(i);
//printf("2 t=%d i=%d\n",t,i);
}
}
}
printf("Case %d: %d\n",kase,n-MaxMatch());
}
return 0;
}