题目
样例输入:
5
2 9 11 12 37
样例输出:
2
数据范围:
剖解题目
给n个数,两两配对,要求是两个数的和必须是素数,配对后就不能再与其他的数配对。
解法
泪奔,学了网络流终于有用了/(ㄒoㄒ)/。
~~尽管这道题很裸
由于ai很小,我们直接预处理出2000内的质数。
首先我们知道,如果两个数加起来要是个素数,他们首先得一奇数一偶数。
把奇数和偶数分为两类,这就是个二分图,做一遍最大匹配即可。
匈牙利或网络流都行。
最近我刚学网络流,所以就扔了网络流进去,尽管是一个最基础的。。。
代码
具体来讲,就是每一个奇数向能与它的和为质数的偶数连一条容量为1的边,然后源点向每一个奇数连一条容量为1的边,每一个偶数向汇点连一个容量为1的边。
手速upupupup。。。
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=42,maxm=2002;
int f[maxn][maxn],a[maxn],h[maxn];
int n,ans,id;
bool bz[maxm];
int aug(int x,int now)
{
if (x==n+1) return now;
h[x]=id;
fo(i,0,n+1)
if (h[i]<id&&f[x][i]){
int k=aug(i,min(now,f[x][i]));
if (k){
f[x][i]-=k;
f[i][x]+=k;
return k;
}
}
return 0;
}
int main()
{
freopen("prime.in","r",stdin);
freopen("prime.out","w",stdout);
scanf("%d",&n);
int maxx=0;
fo(i,1,n) scanf("%d",&a[i]),maxx=max(maxx,a[i]);
maxx*=2;
fo(i,2,maxx)
if (!bz[i]){
fo(j,2,maxx/i) bz[i*j]=true;
}
fo(i,1,n)
if (a[i]%2) {
f[0][i]=1;
fo(j,1,n)
if (a[j]%2==0) f[i][j]=bz[a[i]+a[j]]^1;
}
else f[i][n+1]=1;
int flow=0;
do{
++id;
flow=aug(0,10000);
ans+=flow;
}while (flow);
printf("%d",ans);
}