桌子上有 mm 张蓝色卡片与 nn 张红色卡片,每张卡片上有一个大于 1 的整数。
现在你要从桌子上拿走一些卡片,分若干次拿。每次只能拿走一组卡片:这组卡片颜色不同,并且两张卡片上面的数字的最大公约数大于 1。
问:最多可以从桌上拿走多少组卡片。
#include <iostream> #include <algorithm> #include <queue> #include <cstring> using namespace std ; const int N=1e6+2,M=N*2,NN=36000; int red,blue,total; int bin[NN],id[NN] ; #define inf 0x3f3f3f3f int R[N],a[N]; int all=1,hd[N],go[M],w[M],nxt[M]; int S,T; int dis[M],ans=0,now[M]; void add_(int x,int y,int z){ nxt[++all]=hd[x]; hd[x]=all; go[all]=y; w[all]=z; swap(x,y); nxt[++all]=hd[x]; hd[x]=all; go[all]=y; w[all]=0; } bool bfs(){ memset(dis,0x3f,sizeof dis); queue<int> q; q.push(S); now[S]=hd[S]; dis[S]=0; while(q.empty()==0){ int x=q.front(); q.pop(); for(int i=hd[x];i;i=nxt[i]){ int y=go[i]; if(w[i]>0&&dis[y]==inf){ dis[y]=dis[x]+1; now[y]=hd[y]; q.push(y); if(y==T) return 1; } } } return 0; } int dfs(int x,int sum){ if(x==T) return sum; int k,res=0; for(int i=now[x];i&∑i=nxt[i]){ now[x]=i; int y=go[i]; if(w[i]>0&&(dis[y]==dis[x]+1)){ k=dfs(y,min(sum,w[i])); if(k==0) dis[y]=inf; w[i]-=k; w[i^1]+=k; res+=k; sum-=k; } } return res; } void Div(int x,int num){ int i,len=0; for(i=2;i*i<=num;i++){ if(num%i==0){ bin[++len]=i; while(num%i==0) num/=i; } } if(num>1) bin[++len]=num; for(i=1;i<=len;i++){ int t=bin[i]; if(id[t]==0) id[t]=++total; add_(x,red+blue+id[t],1); } } void Div2(int x,int num){ int i,len=0; for(i=2;i*i<=num;i++){ if(num%i==0){ bin[++len]=i; while(num%i==0) num/=i; } } if(num>1) bin[++len]=num; for(i=1;i<=len;i++){ int t=bin[i]; if(id[t]) add_(blue+red+id[t],x,1); } } void solve(){ total=0; memset(hd,0,sizeof hd);memset(id,0,sizeof id); all=1; cin>>blue>>red; int i,t; for(i=1;i<=blue;i++) add_(0,i,1); for(i=1;i<=blue;i++){ cin>>t; Div(i,t); } for(i=1;i<=red;i++){ cin>>t; Div2(blue+i,t); } for(i=1;i<=red;i++){ add_(i+blue,red+blue+total+1,1); } S=0, T=blue+red+total+1; int ans=0; while(bfs()) ans+=dfs(S,inf); cout<<ans<<endl; } signed main(){ int tes; cin>>tes; while(tes--) solve(); }
标签:卡片,int,P2065,TJOI2011,go,now,hd,dis From: https://www.cnblogs.com/towboa/p/17207740.html