题目链接:https://codeforces.com/contest/512/problem/C
题目大意:
给出一些狐狸,每只狐狸都有一个权值 a i a_i ai,现在你要把这些狐狸放到圆桌上吃饭,使得每个桌子上的狐狸必须要大于等于3个,并且任意两个相邻的狐狸 a i a_i ai相加均为质数,输出分组方案。
题目思路:
这个题属于一个建模题…
把图建好,就很容易想了
首先考虑 a i + a k a_i + a_k ai+ak是质数这个条件,怎么启发
质数一定是一个奇数,那么只有偶数 + + + 奇数,才会得到奇数
所以奇数和奇数 之间不可能连边,所以这就可以构成一个二分图
令奇数作为左集,偶数作为右集
那么就可以直接根据相邻和为质数进行建边,那么可以根据网络流的性质得出在这个二分图上的每一条增广路都是一个分组的组合。
考虑判断是否存在解,因为最后的圆桌的长度一定是个偶数,因为奇数就会导致奇数奇数挨着必无解
,所以可以考虑最终状态必然是,每一个奇数都对应了两个偶数,所以从源点 到 奇数 增加一条容量为 2 2 2的边,从偶数到汇点增加一条容量为 2 2 2的边。最后只需要判断最大流是否为n即可
Code:
/*** keep hungry and calm CoolGuang! ***/
/*#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)*/
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 5e5+700;
const int mod= 998244353;
const int up = 1e9;
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int num[maxn],b[maxn];
///网络流
struct Dinic{
ll cnt = 2;
struct Edge{
int e,next;
ll w;
};
int _S,_T,N;
int head[maxn],d[maxn],cur[maxn];
Edge edge[maxn];
void _inint(int s,int t,int n){
///n包括S与T
memset(head,0,sizeof(head));
cnt = 2;
_S = s,_T = t,N = n;
}
void addedge(int u,int v,ll w){
edge[cnt] = Edge{
v,head[u],w};
head[u] = cnt++;
}
void Add(int u,int v,ll w){
addedge(u,v,w);addedge(v,u,0);
///输出建图 用于debug 一般情况注释
//printf("%c %lld=[%d %d]%c\n",u==_S?'S':' ',w,u,v,v==_T?'T':' ');
}
bool bfs(){
for(int k=0;k<=N;k++) d[k] = 0;
queue<int>q;q.push(_S);d[_S] = 1;
while(!q.empty()){
int u = q.front();q.pop();
for(int i=head[u];i;i=edge[i].next){
int e = edge[i].e;
if(edge[i].w <= 0||d[e]) continue;
d[e] = d[u]+1;
q.push(e);
}
}
for(int k=0;k<=N;k++) cur[k] = head[k];
return (d[_T] != 0);
}
ll dfs(int u,ll flow){
if(u == _T)return flow;///找到可行流
for(int &i=cur[u];i;i=edge[i].next){
int e = edge[i].e;
if(d[e]!=d[u]+1||edge[i].w<=0) continue;
ll temp = dfs(e,min(flow,edge[i].w));
if(temp<=0) continue;
edge[i].w -= temp;
edge[i^1].w += temp;
return temp;
}
return 0;
}
ll MaxFlow(){
ll maxflow = 0,delta = 0;
while(bfs()){
while(delta = dfs(_S,INF)) maxflow+= delta;
}return maxflow;
}
vector<int>v[maxn];
int col[maxn];
vector<vector<int>>res;
void dfs(int u,vector<int>&a){
col[u] = 1;
a.push_back(u);
for(int e:v[u]){
if(col[e]) continue;
dfs(e,a);
}
}
void AC(){
ll temp = MaxFlow();
if(temp == N-1){
for(int i=1;i<=n;i++){
if(!(num[i]&1))continue;
for(int k=head[i];k;k=edge[k].next){
int e = edge[k].e;
if(edge[k^1].w){
v[e].push_back(i);
v[i].push_back(e);
}
}
}
for(int i=1;i<=n;i++){
if(!col[i]){
vector<int>temp;
dfs(i,temp);
res.push_back(temp);
}
}
printf("%d\n",res.size());
for(auto x:res){
printf("%d ",x.size());
for(int y:x)
printf("%d ",y);
printf("\n");
}
}
else printf("Impossible\n");
}
}g;
int judge(int x){
for(int i=2;i*i<=x;i++)
if(x%i == 0)
return 0;
return 1;
}
int main(){
read(n);
g._inint(0,n+1,n+1);
for(int i=1;i<=n;i++){
read(num[i]);
if(num[i]&1) g.Add(0,i,2);
else g.Add(i,n+1,2);
}
for(int i=1;i<=n;i++){
for(int k=i+1;k<=n;k++){
if(judge(num[i] + num[k])){
if(num[i]&1) g.Add(i,k,1);
else g.Add(k,i,1);
}
}
}
g.AC();
return 0;
}
/***
****/