传送门biu~
最暴力的做法是构建二分图,也就是暴力枚举X和Y中的两张卡牌能否配对然后连边跑最大匹配。
如果想优化这个算法,可以考虑在二分图左右之间再建一排点,使得左右能匹配的两张卡牌可以连向同一个点。设有三类节点
(a,b),(a,c),(b,c)
代表
X
和
于是一个有70000个点,4000000条弧的网络流图诞生了。因为是分层图,所以Dinic的时间复杂度十分优秀。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n1,n2,S,T;
struct Card{int a,b,c;}x[30005],y[30005];
int _head[205],_nex[40005],_to[40005],_tp;
inline void _add(int x,int y){
_nex[++_tp]=_head[x];
_head[x]=_tp;
_to[_tp]=y;
}
int prime[205];bool b[205];
inline void getprime(){
for(int i=2;i<=200;++i){
if(!b[i]) prime[++prime[0]]=i;
for(int j=1;j<=prime[0] && i*prime[j]<=200;++j){
b[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
for(int i=2;i<=200;++i)
for(int j=1;j<=prime[0];++j)
if(i%prime[j]==0) _add(i,j);
}
int fir[70005],head[70005],dep[70005],nex[4000005],to[4000005],cap[4000005],tp=1,prm[50][50];
inline void add(int x,int y,int c){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
cap[tp]=c;
}
inline void Insert(int x,int y){add(x,y,1);add(y,x,0);}
inline void build1(int p){
for(int i=_head[x[p].a];i;i=_nex[i])
for(int j=_head[x[p].b];j;j=_nex[j])
Insert(p,n1+n2+prm[_to[i]][_to[j]]);
for(int i=_head[x[p].a];i;i=_nex[i])
for(int j=_head[x[p].c];j;j=_nex[j])
Insert(p,n1+n2+46*46+prm[_to[i]][_to[j]]);
for(int i=_head[x[p].b];i;i=_nex[i])
for(int j=_head[x[p].c];j;j=_nex[j])
Insert(p,n1+n2+46*46*2+prm[_to[i]][_to[j]]);
}
inline void build2(int p){
for(int i=_head[y[p].a];i;i=_nex[i])
for(int j=_head[y[p].b];j;j=_nex[j])
Insert(n1+n2+prm[_to[i]][_to[j]],n1+p);
for(int i=_head[y[p].a];i;i=_nex[i])
for(int j=_head[y[p].c];j;j=_nex[j])
Insert(n1+n2+46*46+prm[_to[i]][_to[j]],n1+p);
for(int i=_head[y[p].b];i;i=_nex[i])
for(int j=_head[y[p].c];j;j=_nex[j])
Insert(n1+n2+46*46*2+prm[_to[i]][_to[j]],n1+p);
}
inline void solve(){
int num=0;
for(int i=1;i<=46;++i)
for(int j=1;j<=46;++j)
prm[i][j]=++num;
S=n1+n2+3*46*46+1;T=n1+n2+3*46*46+2;
for(int i=1;i<=n1;++i)
Insert(S,i),build1(i);
for(int i=1;i<=n2;++i)
Insert(n1+i,T),build2(i);
}
inline int bfs(){
memset(dep,0,sizeof(dep));
dep[S]=1;queue<int>q;
q.push(S);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nex[i]){
if(cap[i] && !dep[to[i]]){
dep[to[i]]=dep[x]+1;
q.push(to[i]);
}
}
}
return dep[T];
}
int dfs(int x,int now){
if(x==T || !now) return now;
int c=0;
for(int &i=fir[x];i;i=nex[i]){
if(dep[to[i]]==dep[x]+1 && cap[i]){
int f=dfs(to[i],min(now,cap[i]));
now-=f;
cap[i]-=f;
cap[i^1]+=f;
c+=f;
if(!now) break;
}
}
return c;
}
inline int Dinic(){
int c=0;
while(bfs()){
for(int i=1;i<=n1+n2+3*46*46+2;++i) fir[i]=head[i];
c+=dfs(S,INF);
}
return c;
}
int main(){
scanf("%d%d",&n1,&n2);
for(int i=1;i<=n1;++i) scanf("%d%d%d",&x[i].a,&x[i].b,&x[i].c);
for(int i=1;i<=n2;++i) scanf("%d%d%d",&y[i].a,&y[i].b,&y[i].c);
getprime();solve();
printf("%d",Dinic());
return 0;
}