每个数的取值范围是[2,30000] ,因为素数的话,除了2是偶数,其他是奇数——而现在不可能出现2了,所以我们只考虑奇数的素数 。
2个数的和是奇数,有什么情况呢? 只有奇数+偶数
所以,我们把这些数分成2堆——奇数和偶数,然后在他们中间,和是素数的,连上一条边,然后做匹配。
说明了得到的图一定是二分图。
因为对二分图的最大匹配,有一个简单很多的算法,匈牙利算法。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
bool prime[60005];
void init()
{
memset(prime,true,sizeof(prime));
prime[0] = false; prime[1] = false;
for(int i = 2;i <= 60000;++i){
if(prime[i]){
if(i * i > 60000) break;
for(int j = i * i;j <= 60000;j += i){
prime[j] = false;
}
}
}
}
int n;
vector<int>ve[105];
int a[105];
bool vis[105];
int cc[105];
bool dfs(int u)
{
int len = ve[u].size();
for(int i = 0;i < len;++i){
int v = ve[u][i];
if(!vis[v]){
vis[v] = true;
if(cc[v] == -1 || dfs(cc[v])){
cc[u] = v;
cc[v] = u;
return true;
}
}
}
return false;
}
void solve()
{
int ans = 0;
memset(cc,-1,sizeof(cc));
for(int i = 1;i <= n;++i){
if(cc[i] == -1){
memset(vis,false,sizeof(vis));
vis[i] = true;
ans += dfs(i);
}
}
cout << ans << endl;
}
int main()
{
while(~scanf("%d",&n)){
init();
for(int i = 1;i <= n;++i){
ve[i].clear();
scanf("%d",&a[i]);
}
for(int i = 1;i <= n;++i){
for(int j = i + 1;j <= n;++j){
if(prime[a[i] + a[j]]){
ve[i].pb(j);
ve[j].pb(i);
}
}
}
solve();
}
return 0;
}
匈牙利算法的伪代码和实际代码:
cx[i]表示与X部i点匹配的Y部顶点编号
cy[i]表示与Y部i点匹配的X部顶点编号
//伪代码
bool dfs(int u)//寻找从u出发的增广路径
{
for each v∈u的邻接点
if(v未访问){
标记v已访问;
if(v未匹配||dfs(cy[v])){
cx[u]=v;
cy[v]=u;
return true;//有从u出发的增广路径
}
}
return false;//无法找到从u出发的增广路径
}
//代码
bool dfs(int u){
for(int v=1;v<=m;v++)
if(t[u][v]&&!vis[v]){
vis[v]=1;
if(cy[v]==-1||dfs(cy[v])){
cx[u]=v;cy[v]=u;
return 1;
}
}
return 0;
}
void maxmatch()//匈牙利算法主函数
{
int ans=0;
memset(cx,0xff,sizeof cx);
memset(cy,0xff,sizeof cy);
for(int i=0;i<=nx;i++)
if(cx[i]==-1)//如果i未匹配
{
memset(visit,false,sizeof(visit)) ;
ans += dfs(i);
}
return ans ;
}