题面:
题意:
给出n个人, 以及每个人的值ai, 要求他们坐在一些桌子上面, 每个桌子如果有人坐, 就必须做3个人以上。 并且相邻的两个人的值加起来必须是素数。每个人的值都>=2.
题解:
由大于等于2这个条件, 可以知道出现的素数都是奇数(若相邻两个人的值的和为素数,那么一定是奇数), 那么很明显就需要一奇一偶相邻这样做, 那么一个桌子上必定有偶数个人。 一个奇数旁边有两个偶数, 一个偶数旁边有两个奇数。
①、那么我们建立一个源点,将源点连入各个奇数节点,设定权值为2,表示其可以有两个相邻的小伙伴。
②、那么我们再建立一个汇点,将各个偶数节点连入汇点,设定权值为2,表示其可以有两个相邻的小伙伴。
③、那么如果左边某个奇数加上右边某个偶数能够构成一个素数,那么其建一条有向边,从奇数连入偶数,设定权值为1.
这样跑一遍网络流, 看结果是否等于n(是否满流), 如果不相等, 说明不可能。如果相等, dfs一下就可以求出几个桌子, 每个桌子上面几个人了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define pr make_pair
#define pb push_back
#define ui unsigned int
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define forhead(x) for(int i=head[(x)];i;i=nt[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1000000007;
const double eps=1e-8;
const double pi=acos(-1.0);
const int maxn=210;
const int maxm=50100;
const int up=100000;
int head[maxn],ver[maxm],edge[maxm],nt[maxm],tot=1;
int d[maxn],a[maxn];
int n,s,t;
bool hh[maxn];
queue<int>q;
vector<int>vc[maxn];
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z,nt[tot]=head[x],head[x]=tot;
ver[++tot]=x,edge[tot]=0,nt[tot]=head[y],head[y]=tot;
}
bool bfs(void)
{
memset(d,0,sizeof(d));
while(q.size()) q.pop();
q.push(s);
d[s]=1;
while(q.size())
{
int x=q.front();
q.pop();
forhead(x)
{
int y=ver[i];
if(edge[i]&&!d[y])
{
q.push(y);
d[y]=d[x]+1;
if(y==t) return true;
}
}
}
return false;
}
int dinic(int x,int flow)
{
if(x==t) return flow;
int rest=flow ,k;
for(int i=head[x];i&&rest;i=nt[i])
{
int y=ver[i];
if(edge[i]&&d[y]==d[x]+1)
{
k=dinic(y,min(rest,edge[i]));
if(!k) d[y]=0;
edge[i]-=k;
edge[i^1]+=k;
rest-=k;
}
}
return flow-rest;
}
int getmaxx(void)
{
int flow=0,maxflow=0;
while(bfs())
while(flow=dinic(s,inf))
maxflow+=flow;
return maxflow;
}
int prime[maxm],cnt=0;
bool ha[maxm];
void Prime(void)
{
ha[1]=true;
for(int i=2;i<maxm;i++)
{
if(!ha[i]) prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<maxm;j++)
{
ha[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
void dfs(int x,int cnt)
{
vc[cnt].pb(x);
hh[x]=true;
forhead(x)
{
int y=ver[i];
if(hh[y]) continue;
if(y==s||y==t) continue;
if((i&1)==0&&edge[i]==0)
dfs(y,cnt);
else if((i&1)!=0&&edge[i]!=0)
dfs(y,cnt);
}
}
int main(void)
{
Prime();
int n;
scanf("%d",&n);
s=n+1,t=s+1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]&1) add(s,i,2);
else add(i,t,2);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((a[i]&1)&&!(a[j]&1))
{
if(!ha[a[i]+a[j]])
add(i,j,1);
}
}
}
int ans=getmaxx();
if(ans!=n)
{
printf("Impossible\n");
return 0;
}
int res=0;
for(int i=1;i<=n;i++)
{
if(!hh[i])
dfs(i,++res);
}
cout<<res<<endl;
for(int i=1;i<=res;i++)
{
printf("%d ",vc[i].size());
for(auto x:vc[i])
printf("%d ",x);
putchar('\n');
}
return 0;
}