高维宇宙 【NOIP2016提高A组集训第3场10.31】

来源:互联网 发布:newman 网络引论 编辑:程序博客网 时间:2024/06/04 23:32

题目

这里写图片描述
样例输入:
这里写图片描述
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);}

这里写图片描述

0 0
原创粉丝点击