ZOJ 3988 Prime Set (最大匹配)

来源:互联网 发布:vi保存退出ubuntu 编辑:程序博客网 时间:2024/05/17 23:09
Prime Set

Time Limit: 2 Seconds      Memory Limit: 131072 KB

Given an array of integers, we say a setis a prime set of the given array, ifandis prime.

BaoBao has just found an array of integersin his pocket. He would like to select at mostprime set of that array to maximize the size of the union of the selected sets. That is to say, to maximize by carefully selectingand, whereandis a prime set of the given array. Please help BaoBao calculate the maximum size of the union set.

Input

There are multiple test cases. The first line of the input is an integer , indicating the number of test cases. For each test case:

The first line contains two integers and(,), their meanings are described above.

The second line contains integers(), indicating the given array.

It's guaranteed that the sum of over all test cases will not exceed.

Output

For each test case output one line containing one integer, indicating the maximum size of the union of at mostprime set of the given array.

Sample Input

44 22 3 4 55 33 4 12 3 66 31 3 6 8 1 11 01

Sample Output

4360

Hint

For the first sample test case, there are 3 prime sets: {1, 2}, {1, 4} and {2, 3}. As, we can select {1, 4} and {2, 3} to get the largest union set {1, 2, 3, 4} with a size of 4.

For the second sample test case, there are only 2 prime sets: {1, 2} and {2, 4}. As, we can select both of them to get the largest union set {1, 2, 4} with a size of 3.

For the third sample test case, there are 7 prime sets: {1, 3}, {1, 5}, {1, 6}, {2, 4}, {3, 5}, {3, 6} and {5, 6}. As, we can select {1, 3}, {2, 4} and {5, 6} to get the largest union set {1, 2, 3, 4, 5, 6} with a size of 6.





题意:
有n个数,如果两个数相加为一个素数的话,那么这两个数可以构成一个素数组(素数组里面放的是这个两个数的下标)。要求你从中取k个组,并把这k个组求并,使得最后求并后的集合里面元素的个数最大

解析:
两个可以为一组的数就可以建边。
这里组成素数有条件:一定是一奇一偶(因为除了2以外,素数一定是奇数,而只有奇+偶=奇),这样就很符合二分图的特性,奇数放一边,偶数放一边。
这里需要仔细考虑的就是1的情况,因为1+1=2,1一定首先跟其他奇数一样,去跟偶数做最大匹配(因为1 1 4 6,k=2,这组样例,1一开始就跟1匹配的话,答案就只能是3,而若1跟4,6匹配的话,就可以得到两个二元组(1,4)(1,6)),并且1一定要最后进行最大匹配,因为1若匹配了其他奇数应该匹配的偶数,而1还可以和另一个1达成匹配,那样匹配数少1,所以先让其他奇数匹配完,1看看能不能使最大匹配数更大,即使无法变大,1也可以跟另外的1匹配,使匹配数增大。
最后就是求在可以构成素数组的数中,找那些未被匹配的数,一旦k>最大匹配数,就可以把这些数加进去。

注意:这里最大匹配存图的时候一定要用VECTOR,不然会T的!!!

理解1情况的几组样例
5
4 5
1 8 3 1
4 2
1 1 6 2
6 2
1 1 6 2 1 1
4 2
1 1 4 6
3 5
1 8 3

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int MAXN = 1e6+10;const int M = 3000+100;int a[M];int prime[MAXN*2],cnt;   //0表示素数vector<int> map[M];    //int visit[M];int f[M],n,k;int B[M],resn;void primeTable(){cnt=0;memset(prime,0,sizeof(prime));prime[0]=prime[1]=1;for(int i=2;i<MAXN*2 ;i++){if(!prime[i]){for(int j=i+i;j<MAXN*2 ;j+=i)prime[j]=1;}}}int Hungary(int x){//f[x]=1;for(int i=0;i<map[x].size();i++)   //!!存图用vector,原因用矩阵存每次要遍历n个点,时间复杂度太大了{int u=map[x][i];if(f[u]==0){f[u]=1;if(B[u]==-1||Hungary(B[u])){B[u]=x;B[x]=u;return 1;}}}return 0;}int cmp(int a,int b){return a>b;}int main(){int t,nonev;scanf("%d",&t);primeTable();while(t--){int num=0;nonev=0;scanf("%d%d",&n,&k);for(int i=0;i<n;i++){scanf("%d",&a[i]);B[i]=-2;map[i].clear();}sort(a,a+n,cmp);for(int i=0;i<n;i++)   //建立二分图{for(int j=i+1;j<n;j++){if(!prime[a[i]+a[j]]){B[i]=B[j]=-1;if(a[i]==1&&a[j]==1) continue;if(a[i]%2)map[i].push_back(j);elsemap[j].push_back(i);}}}int ans=0;for(int i=0;i<n;i++){if(a[i]%2&&B[i]==-1)  //只对奇数且度数不为0的点进行搜索{memset(f,0,sizeof(f));if(Hungary(i)){ans++;}}}int single=0;for(int i=0;i<n;i++){if((B[i]==-2||B[i]==-1)&&a[i]==1)   //单个的1{single++;}if(B[i]==-2)   //度数为0的点{nonev++;}}ans+=single/2;   //二元组个数resn=n-nonev-ans*2;   //剩余单元组个数if(ans>=k){printf("%d\n",k*2);}else{if(k-ans>resn){printf("%d\n",ans*2+resn);}else{printf("%d\n",ans+k);}}}return 0;}



原创粉丝点击