#二分圖匹配#洛谷 5771 [JSOI2016]反質數序列
阿新 • • 發佈:2021-10-19
二分圖匹配
題目
給出 \(n\) 個正整數,問最大的子集使得任意兩個數的和都不是質數
\(n\leq 3*10^3\)
分析
如果把兩個數的和為質數連邊,等價於求最大獨立集。
由於只有偶數加奇數才可能產生質數(1+1除外),所以可以根據其奇偶性分成兩部分,
那求一個二分圖匹配即可,注意最大獨立集最多隻能有一個1
程式碼
#include <cstdio> #include <cctype> #define rr register using namespace std; const int N=3011,M=200011; struct node{int y,next;}e[N*N/4]; int v[M],prime[M],Cnt,flag,odd[N],even[N],link[N],upd,as[N],et,ans; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline void Pro(int n){ v[1]=1; for (rr int i=2;i<=n;++i){ if (!v[i]) prime[++Cnt]=i; for (rr int j=1;j<=Cnt&&prime[j]<=n/i;++j){ v[i*prime[j]]=1; if (i%prime[j]==0) break; } } } inline bool match(int x){ for (rr int i=as[x];i;i=e[i].next) if (v[e[i].y]!=upd){ rr int q=link[e[i].y]; link[e[i].y]=x,v[e[i].y]=upd; if (!q||match(q)) return 1; link[e[i].y]=q; } return 0; } signed main(){ Pro(200000),flag=upd=1; for (rr int T=iut();T;--T){ rr int x=iut(); if (x%2==0) even[++even[0]]=x; else if (x>1) odd[++odd[0]]=x; else if (x==1&&flag) flag=0,odd[++odd[0]]=x; } for (rr int i=1;i<=odd[0];++i) for (rr int j=1;j<=even[0];++j) if (!v[odd[i]+even[j]]) e[++et]=(node){j,as[i]},as[i]=et; for (rr int i=1;i<=odd[0];++i) ++upd,ans+=match(i); return !printf("%d",odd[0]+even[0]-ans); }