2017 CCPC秦皇島 H Prime Set(二分圖匹配)

是一個二分圖匹配

而我和舟神bbbbbbbbbbbbbbbbb了大概一個小時,不想寫二分圖,甚至想建網絡流模型

我也是服了,可能這就是不會算時間複雜度的菜雞吧

題目思路:

1.打素數表

2.將奇數和偶數分開到兩邊,因爲只有奇數加偶數纔可以是素數。

3.1特殊處理,如果有兩個1,1之間也可以匹配,但優先考慮1和偶數的匹配,此處要注意細節,我用了兩個set來減少討論

#include<iostream>
#include<set>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#define N 3005 
#define MAXN 2000005
using namespace std;
int eve[N],odd[N];
bool isprime[MAXN];
int prime[150005],tot=0;

void init(){
	memset(isprime,true,sizeof(isprime));
	isprime[1]=false;
	for(int i=2;i<=MAXN-1;i++){
        if(isprime[i]){
            prime[++tot]=i;
        }
        for(int j=1;j<=tot;j++){
            if(i*prime[j]>MAXN-1) break;
            isprime[i*prime[j]]=0;
            if(i%prime[j]==0) break;
        }
    }
    //for (int i=1;i<=20;i++) cout<<i<<" "<<isprime[i]<<endl;
}

int head[N];
struct edge{
	int v,next;
}e[N*N];
void add(int u, int v){
	e[++tot]=(edge){v,head[u]};
	head[u]=tot;
}

bool vis[N];
int link[N];
int dfs(int s){
	//vis[s]=1; ?????
	for(int i=head[s];i!=-1;i=e[i].next){
		int t=e[i].v;
		if(!vis[t]){
			vis[t]=1;
			if(link[t]==-1||dfs(link[t])){
				link[t]=s;
				link[s]=t;
				return 1;
			}
		}
	}
	return 0;
}
 
int max_matching(int n)
{
	int ans=0;
	for(int i=1;i<=n;i++){
		if (link[i]==-1){
			memset(vis,0,sizeof(vis));
			ans+=dfs(i);
		}
	}
	return ans;
}
set<int>sodd,seven;

int main(){
	init();
	int T;
	scanf("%d",&T);
	while (T--){
		int n,k,tot1=0,tot2=0,x;
		scanf("%d%d",&n,&k);
		for (int i=1;i<=n;i++){
			scanf("%d",&x);
			if (x%2) odd[++tot1]=x;
			else eve[++tot2]=x; 
		}
		tot=0;
		memset(head,-1,sizeof(head));
		sodd.clear();
		seven.clear();
		int last1=-1,sum1=0;
		for (int i=1;i<=tot1;i++){
			if (odd[i]==1){
				if (!sum1) last1=i,sum1++;
				else{
					if (sum1==1) sodd.insert(last1);
					sodd.insert(i);
					sum1++;
				}
			}
			for (int j=1;j<=tot2;j++){
				if (isprime[odd[i]+eve[j]]){
					add(i,tot1+j);
					add(tot1+j,i);
					sodd.insert(i);
					seven.insert(j);
				}
			}
		}
		memset(link,-1,sizeof(link));
		int mat=max_matching(tot1);
		//cout<<mat<<endl;
		//for (int i=1;i<=tot1+tot2;i++) printf("link%d\n",link[i]);
		
		if (mat>=k) printf("%d\n",k*2);
		else{
			int tmp=0;
			for (int i=1;i<=tot1;i++){
				if (odd[i]==1&&link[i]==-1) tmp++;
			}
			int ans=mat*2+tmp/2*2;
			if (ans>=2*k) printf("%d\n",k*2);
			else {
				ans=min(k*2,min(ans+k-mat-tmp/2,(int)sodd.size()+(int)seven.size()));
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}

/*
10
5 5 
1 1 1 1 1 
6 5
1 1 1 1 2 2
6 3
1 1 1 1 1 3
6
5 5
1 1 1 1 1

*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章