题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3988
这个题,要是在赛场上估计会出的快一点?邻接矩阵被卡,一的情况加很多特判?很让人绝望啊。思路就是奇偶分开讨论,然后发现只有1和1能够连边,先不把1之间连边,然后跑匈牙利,然后在判断有多少个1没有被匹配,然后将它两两匹配,然后判断能不能用满k,如果不能就把剩下的一个一个加进去。就是将1的情况好好讨论一下。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3005;
const int M=2e6+10;
int n,k;
int prime[M],a[MAXN];//保存素数
bool vis[M];//初始化
int cnt=0;
vector<int> uN,vN;//u,v的数目,使用前面必须赋值
int linker[MAXN];
bool used[MAXN],book[MAXN];
void Prime()
{
memset(vis,0,sizeof(vis));
for(int i=2;i<M;i++)
{
if(!vis[i])
prime[cnt++]=i;
for(int j=0;j<cnt&&i*prime[j]<M;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)//关键
break;
}
}
}
const int MAXM=1e7;//边数的最大值
struct Edge
{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[tot].to=v;edge[tot].next=head[u];
head[u]=tot++;
}
bool dfs(int u)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!used[v])
{
used[v]=true;
if(linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int res=0;
memset(linker,-1,sizeof(linker));
for(int u=0;u<uN.size();u++)
{
memset(used,false,sizeof(used));
if(dfs(uN[u]))res++;
}
return res;
}
void build()
{
init();
uN.clear();vN.clear();
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(!vis[a[i]+a[j]]&&(!(a[i]==1&&a[j]==1)))
{
addedge(i,j);
addedge(j,i);
}
}
}
for(int i=1;i<=n;i++)
{
if(a[i]%2==1)
{
uN.push_back(i);
}
else
{
vN.push_back(i);
}
}
}
void solve()
{
int ans=0,Count=0,o=0,sz=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build();
ans=hungary();
memset(book,false,sizeof(book));
for(int i=1;i<=n;i++)
{
if(linker[i]!=-1)
{
book[i]=book[linker[i]]=true;
}
}
for(int i=1;i<=n;i++)
{
if(a[i]==1&&!book[i])
{
o++;
}
}
ans+=o/2;
sz=(o%2)?o-1:o;
for(int i=1;i<=n&&sz;i++)
{
if(a[i]==1&&(!book[i]))
{
book[i]=true;
sz--;
}
}
if(ans>=k)
{
printf("%d\n",2*k);
return ;
}
k-=ans;
ans*=2;
if(o%2==1&&o>1)
{
ans++;
k--;
for(int i=1;i<=n;i++)
{
if(a[i]==1&&(!book[i]))
{
book[i]=true;
}
}
}
for(int i=1;i<=n&&k;i++)
{
if(book[i])
continue;
if(head[i]!=-1)
{
ans++;
k--;
}
}
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
Prime();
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}