1. 程式人生 > >ZOJ-3988 2017CCPC-秦皇島 Prime Set 二分圖最大匹配 匈牙利

ZOJ-3988 2017CCPC-秦皇島 Prime Set 二分圖最大匹配 匈牙利

tor names 現在 i++ show 人的 include prim pro

題面

題意:給你n個數,你可以選擇2個和為質數的數為一對,每個數可以重復選擇,你最多選k對,問你最多能選多少個不同數出來

題解:首先思考怎麽樣的數和為質數,2個偶數相加不行,除了1+1以外2個奇數相加不行,那麽大致上,就是偶數+奇數,

這樣很明顯的發現這就是一個二分圖,而且這是自動分好的,並不需要你建邊的時候特殊考慮

所以對於能夠加成質數的組合連邊,跑最大匹配,如果現在有大於等於k個,那答案肯定就是選k個,每個裏面一奇一偶,所以答案==k*2

可要現在不夠k個呢?

還是先選ans*2個,剩下的,最好拿個樣例畫圖出來,我們發現那些沒在最大匹配的點,還可以有連向匹配裏點的邊

,這時候選一條,答案就只能加1

所以答案就加上這種邊的數量,當然也要小於總邊數也要小於k,

(這裏其實就利用匹配裏的"板凳數組",初始化-1,有板凳坐就是0,最後剩下還是0的那些就是可以連一條邊的)

那些人的題解好像對1進行特殊處理,搞的很復雜麻煩,可是我們再細想,選1+1這對,前提是1沒法和任何數相加為質數了,不然選不到1+1,且收益也只有1

因為1+1只能帶來1這個1個數,所以不用考慮,它本身就不會被納入最大匹配裏,這條邊,只有在需要補的時候用上

 1 #include<bits/stdc++.h>
 2
#define N 3005 3 #define M 2000010 4 using namespace std; 5 int pri[M],n,k,T,ans,sum,a[N],used[N],col[N]; 6 vector<int>g[N]; 7 int dfs(int x) 8 { 9 used[x]=1; 10 for (int i=0;i<g[x].size();i++) 11 { 12 int y=g[x][i]; 13 if (!used[y]) 14 { 15 used[y]=1
; 16 if (col[y]==0 || dfs(col[y])) 17 { 18 col[y]=x; 19 col[x]=y; 20 return 1; 21 } 22 } 23 } 24 return 0; 25 } 26 int main() 27 { 28 for (int i=2;i<M;i++) 29 if (!pri[i]) 30 for (int j=i*2;j<M;j+=i) pri[j]=1; 31 scanf("%d",&T); 32 while (T--) 33 { 34 scanf("%d%d",&n,&k); 35 memset(col,-1,sizeof(col)); 36 for (int i=1;i<=n;i++) g[i].clear(); 37 ans=sum=0; 38 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 39 for (int i=1;i<=n;i++) 40 for (int j=i+1;j<=n;j++) 41 if (!pri[a[i]+a[j]]) 42 { 43 col[i]=0; 44 col[j]=0; 45 g[i].push_back(j); 46 g[j].push_back(i); 47 } 48 for (int i=1;i<n;i++) 49 if (!col[i]) 50 { 51 memset(used,0,sizeof(used)); 52 ans+=dfs(i); 53 } 54 if (ans>=k) printf("%d\n",k*2);else 55 { 56 for (int i=1;i<=n;i++) if (!col[i]) sum++; 57 printf("%d\n",ans*2+min(k-ans,sum)); 58 } 59 } 60 }

ZOJ-3988 2017CCPC-秦皇島 Prime Set 二分圖最大匹配 匈牙利