题目描述:戳这里
题解:
这题是一道比较猥琐的网络流题。
我们注意到一个质数(>2)肯定是由一个偶数和一个奇数相加得到的。那么我们就可以将奇数和偶数连边,然后跑一趟二分图匹配。但是考虑到每一桌至少要有三个人,而匈牙利算法是无法解决这一条件的,那么就要用网络流来解决。
注意到一个奇数肯定与两个偶数相邻这个条件,那么我们就可以从奇数的节点向偶数的节点连边,流量为1,然后从源点S向奇数点连边,偶数点向T连边,流量均为2,这样就能保证前面的条件。
接下来就只要刷一下DINIC就好了。
如果有答案,就dfs一下,刷出每一组的答案。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=210,maxm=40010,inf=1e8;
int n,S,T,m,tot,a[maxn],lnk[maxn],son[maxm],nxt[maxm],que[maxn],w[maxm],dep[maxn],cur[maxn],fa[maxn],ans[maxn][maxn];
bool check(int x){
int sq=sqrt(x);
for (int i=2;i<=sq;i++) if (x%i==0) return 0;
return 1;
}
void add(int x,int y,int z){
son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;
son[++tot]=x,w[tot]=0,nxt[tot]=lnk[y],lnk[y]=tot;
}
bool bfs(){
int head=0,tail=1; que[tail]=S;
memset(dep,255,sizeof(dep)); dep[S]=0;
while (head<tail){
head++;
for (int j=lnk[que[head]];j!=-1;j=nxt[j])
if (dep[son[j]]==-1&&w[j]>0) {
dep[son[j]]=dep[que[head]]+1; que[++tail]=son[j];
}
}
if (dep[T]==-1) return 0; else return 1;
}
int dfs(int x,int flow){
if (x==T) return flow;
for (int& j=cur[x];j!=-1;j=nxt[j])
if (dep[son[j]]==dep[x]+1&&w[j]!=0){
int x=dfs(son[j],min(flow,w[j]));
if (x) {w[j]-=x; w[j^1]+=x; return x;}
}
return 0;
}
int dinic(){
int ans=0;
while (bfs()){
for (int i=1;i<=T;i++) cur[i]=lnk[i];
int sum; while (sum=dfs(S,inf)) ans+=sum;
}
return ans;
}
void find(int x,int sum){
fa[x]=sum; ans[sum][++ans[sum][0]]=x;
if (a[x]%2==1) {
for (int j=lnk[x];j!=-1;j=nxt[j])
if (w[j]==0&&!fa[son[j]]) find(son[j],sum);
} else {
for (int j=lnk[x];j!=-1;j=nxt[j])
if (w[j^1]==0&&!fa[son[j]]) find(son[j],sum);
}
}
int main(){
tot=-1; memset(lnk,255,sizeof(lnk)); memset(nxt,255,sizeof(nxt));
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
T=n+2,S=n+1;
for (int i=1;i<=n;i++) if (a[i]%2==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]%2==1&&a[j]%2==0&&check(a[j]+a[i])) add(i,j,1);
int flo=dinic();
if (flo!=n) {printf("Impossible\n"); return 0;}
int s=0;
for (int i=1;i<=n;i++) if (!fa[i]) find(i,++s);
printf("%d\n",s);
for (int i=1;i<=s;i++) {
printf("%d ",ans[i][0]);
for (int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
printf("\n");
}
return 0;
}