CCPC.2017秦皇島站-重現賽-H(二分匹配)
阿新 • • 發佈:2018-12-24
題意:給你一個序列,讓你找出不超過k對的數對(i,j)使得a[i]+b[j]是一個質數,並且i!=j,且讓這k對數對組成的
序列的元素儘可能的多,問你最終生成序列的元素個數。
比如: 3 4 3 可以組成2對(1,2)和(2,3)生成的序列就是 3 4 3,呢答案就是3
題解:對於一個質數,本題考慮一定是原陣列的兩個數所組成,數並不是很大,我們可以預處理出所有
能構成質數的組合,將他們之間連條邊,然後考慮跑二分匹配,(其實很容易看出題目中隱藏的二分圖的,因為一個質數一定是由一個奇數和一個偶數構成。。。這樣可能省去大量時間,但我沒這樣寫),在求出圖中最大二分匹配後
處理些細節就好了,比如說二分匹配的對數和k的大小關係。。
#include<vector> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; #define maxm 2000005 vector<int>q[3005]; int a[3005],b[maxm]={1,1},used[3005]; int n,k,flag[3005],link[3005]; void init() { ll i,j; for(i=2;i<maxm;i++) { if(b[i]) continue; for(j=i*i;j<maxm;j+=i) b[j]=1; } } int dfs(int u) { used[u]=1; for(int i=0;i<q[u].size();i++) { int v=q[u][i]; if(used[v]==0) { used[v]=1; if(link[v]==0 || dfs(link[v])) { link[v]=u; link[u]=v; return 1; } } } return 0; } int main(void) { int T; init(); scanf("%d",&T); while(T--) { memset(used,0,sizeof(used)); memset(flag,0,sizeof(flag)); memset(link,0,sizeof(link)); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { if(b[a[i]+a[j]]==0) { q[i].push_back(j); q[j].push_back(i); flag[i]=flag[j]=1; } } int cnt1=0,cnt2=0; for(int i=1;i<=n;i++) if(flag[i] && link[i]==0) { memset(used,0,sizeof(used)); if(dfs(i)) cnt1++; } for(int i=1;i<=n;i++) if(flag[i] && link[i]==0) cnt2++; if(cnt1>=k) printf("%d\n",k*2); else printf("%d\n",cnt1*2+min(k-cnt1,cnt2)); for(int i=1;i<=n;i++) q[i].clear(); } return 0; }