【二分圖最大匹配】【匈牙利算法】zoj3988 Prime Set
阿新 • • 發佈:2017-11-02
奇數 動態 space () print ret min name mes
題意:給你n個正整數,一對和為素數的數為一個合法數對。你選不超過K個合法數對,使得你選的數對涉及到的數的數量最大化。輸出這個值。
所有1之間是可以任意兩兩配對的。
把奇數放在左側,偶數放在右側。
考慮當前要使用多少個“1”,動態更新最大匹配。
如果K不超過 最大匹配數 + 剩下的還沒使用過的1數/2 ,那麽直接輸出這個和*2即可。
否則剩下的用剩余的1(最多一個)+沒被匹配上的但是不孤立(有邊)的點數 補齊,這樣不斷更新答案。
有一個坑點是如果1恰好只有一個的話,而且沒有能和它加起來組成素數的數的話,就要忽略掉這個1。
#include<cstdio> #include<algorithm> #include<cstring> typedef long long ll; using namespace std; int T,n,K,a[3005]; bool notprime[2000005]; bool cmp(const int &a,const int &b){ return a>b; } int e,first[3005],next[3005*3005],v[3005*3005]; void AddEdge(int U,int V){ v[++e]=V; next[e]=first[U]; first[U]=e; } int mat[3005],yi; bool vis[3005]; bool dfs(int U) { for(int i=first[U];i;i=next[i]){ if(!vis[v[i]]){ vis[v[i]]=1; if(mat[v[i]]==-1 || dfs(mat[v[i]])){ mat[v[i]]=U; return 1; } } } return 0; } int ru[3005],ru1[3005],right1,right2; int main(){ notprime[1]=1; for(int i=2;i<=2000000;++i){ for(ll j=(ll)i*(ll)i;j<=2000000ll;j+=(ll)i){ notprime[j]=1; } } scanf("%d",&T); for(;T;--T){ e=0; memset(mat,-1,sizeof(mat)); memset(first,0,sizeof(first)); memset(ru,0,sizeof(ru)); memset(ru1,0,sizeof(ru1)); scanf("%d%d",&n,&K); yi=0; for(int i=1;i<=n;++i){ scanf("%d",&a[i]); if(a[i]==1){ ++yi; } } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(!(a[i]==1 && a[j]==1) && !notprime[a[i]+a[j]]){ if(a[i]&1){ AddEdge(i,j); ++ru[j]; if(a[i]==1){ ++ru1[j]; } } else{ AddEdge(j,i); ++ru[i]; if(a[j]==1){ ++ru1[i]; } } } } } bool tp=(yi==1 ? 1 : 0); right1=right2=0; for(int i=1;i<=n;++i){ if(!(a[i]&1)){ if(ru[i]>ru1[i]){ ++right1; } if(ru[i]){ ++right2; } if(ru1[i]){ tp=0; } } } if(tp){ yi=0; } int sum=0,cnt=0,nowleft=0,ans=0; for(int i=1;i<=n;++i){ if((a[i]&1)){ ++nowleft; if(a[i]!=1 && first[i]){ memset(vis,0,sizeof(vis)); if(dfs(i)){ ++sum; } } else if(a[i]==1 && !tp){ if(!cnt){ if(K<=sum+yi/2){ ans=max(ans,2*K); } else{ ans=max(ans,2*sum+yi+min(K-sum-yi/2-yi%2,nowleft-1+right1-sum*2)); } } ++cnt; memset(vis,0,sizeof(vis)); if(dfs(i)){ ++sum; } if(K<=sum+(yi-cnt)/2){ ans=max(ans,2*K); } else{ ans=max(ans,2*sum+(yi-cnt)+min(K-sum-(yi-cnt)/2-(yi-cnt)%2,nowleft+right2-sum*2)); } } } } if(!cnt){ if(K<=sum){ ans=max(ans,2*K); } else{ ans=max(ans,2*sum+min(K-sum,nowleft+right1-sum*2)); } } printf("%d\n",ans); } return 0; }
【二分圖最大匹配】【匈牙利算法】zoj3988 Prime Set