Codeforces Round #290 (Div. 1) C. Fox And Dinner(最大流)

C. Fox And Dinner
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Fox Ciel is participating in a party in Prime Kingdom. There are n foxes there (include Fox Ciel). The i-th fox is ai years old.

They will have dinner around some round tables. You want to distribute foxes such that:

  1. Each fox is sitting at some table. 
  2. Each table has at least 3 foxes sitting around it. 
  3. The sum of ages of any two adjacent foxes around each table should be a prime number. 

If k foxes f1, f2, ..., fk are sitting around table in clockwise order, then for 1 ≤ i ≤ k - 1: fi and fi + 1 are adjacent, and f1 and fk are also adjacent.

If it is possible to distribute the foxes in the desired manner, find out a way to do that.

Input

The first line contains single integer n (3 ≤ n ≤ 200): the number of foxes in this party. 

The second line contains n integers ai (2 ≤ ai ≤ 104).

Output

If it is impossible to do this, output "Impossible".

Otherwise, in the first line output an integer m (): the number of tables.

Then output m lines, each line should start with an integer k -=– the number of foxes around that table, and then k numbers — indices of fox sitting around that table in clockwise order.

If there are several possible arrangements, output any of them.

Examples
input
4
3 4 8 9
output
1
4 1 2 4 3
input
5
2 2 2 2 2
output
Impossible
input
12
2 3 4 5 6 7 8 9 10 11 12 13
output
1
12 1 2 3 6 5 12 9 8 7 10 11 4
input
24
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
output
3
6 1 2 3 6 5 4
10 7 8 9 12 15 14 13 16 11 10
8 17 18 23 22 19 20 21 24
Note

In example 1, they can sit around one table, their ages are: 3-8-9-4, adjacent sums are: 11, 17, 13 and 7, all those integers are primes.

In example 2, it is not possible: the sum of 2+2 = 4 is not a prime number.

题意:

给出n个人, 以及每个人的值, 要求他们坐在一些桌子上面, 每个桌子如果有人坐, 就必须做3个人以上。 并且相邻的两个人的值加起来必须是素数。每个人的值都>=2.如果可能输出桌子数目ans,接下来ans行首先输出每个桌子的人数,然后顺时针输出每个人的编号。

题解:

由大于等于2这个条件, 可以知道素数都是奇数, 那么很明显就需要一奇一偶相邻这样做, 那么一个桌子上必定有偶数个人。 一个奇数旁边有两个偶数, 一个偶数旁边有两个奇数。

所以可以先判断n是否为偶数, 如果是奇数直接输出不可能。

然后开始奇偶建边, 源点和奇数建边, 权值为2, 因为一个奇数需要和两个偶数匹配; 偶数和汇点建边, 同理权值也为2。

然后, 如果一个奇数和一个偶数相加得到的数是素数, 那么奇数向偶数连一条边, 权值为1。

这样跑一遍网络流, 看结果是否等于n, 如果不相等, 说明不可能。如果可能, dfs一下就可以求出几个桌子, 每个桌子上面几个人了。(在这里我是重新建立了一个无向图,向这个图中加入每条满流边的两个顶点)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;


const int maxn=210;//点数的最大值
const int maxm=20500;//边数的最大值
struct Node
{
    int from,to,next;
    int cap;
}edge[maxm];
int tol;
int dep[maxn];//dep为点的层次
int head[maxn];
void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)//第一条边下标必须为偶数
{
    edge[tol].from=u;
    edge[tol].to=v;
    edge[tol].cap=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].from=v;
    edge[tol].to=u;
    edge[tol].cap=0;
    edge[tol].next=head[v];
    head[v]=tol++;
}
int BFS(int start,int end)
{
    int que[maxn];
    int front,rear;
    front=rear=0;
    memset(dep,-1,sizeof(dep));
    que[rear++]=start;
    dep[start]=0;
    while(front!=rear)
    {
        int u=que[front++];
        if(front==maxn)front=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].cap>0&&dep[v]==-1)
            {
                dep[v]=dep[u]+1;
                que[rear++]=v;
                if(rear>=maxn)rear=0;
                if(v==end)return 1;
            }
        }
    }
    return 0;
}
int dinic(int start,int end)
{
    int res=0;
    int top;
    int stack[maxn];//stack为栈,存储当前增广路
    int cur[maxn];//存储当前点的后继
    while(BFS(start,end))
    {
        memcpy(cur,head,sizeof(head));
        int u=start;
        top=0;
        while(1)
        {
            if(u==end)
            {
                int min=inf;
                int loc;
                for(int i=0;i<top;i++)
                    if(min>edge[stack[i]].cap)
                    {
                        min=edge[stack[i]].cap;
                        loc=i;
                    }
                for(int i=0;i<top;i++)
                {
                    edge[stack[i]].cap-=min;
                    edge[stack[i]^1].cap+=min;
                }
                res+=min;
                top=loc;
                u=edge[stack[top]].from;
            }
            for(int i=cur[u];i!=-1;cur[u]=i=edge[i].next)
                if(edge[i].cap!=0&&dep[u]+1==dep[edge[i].to])
                    break;
            if(cur[u]!=-1)
            {
                stack[top++]=cur[u];
                u=edge[cur[u]].to;
            }
            else
            {
                if(top==0)break;
                dep[u]=-1;
                u=edge[stack[--top]].from;
            }
        }
    }
    return res;
}
const int N=2e4+100;
int prime[N];
bool is[N];
void getPrim()
{
    for(int i=2;i<N;i++)
    {
        if(!prime[i])
        {
            prime[++prime[0]] = i;
        }
        for(int j=1;(j<=prime[0])&&(i*prime[j]<N);j++)
        {
            prime[prime[j]*i] = 1;
            if(i%prime[j]==0) break;
        }
    }
}
void get()
{
    getPrim();
    memset(is,false,sizeof(is));
    for(int i=1;i<=prime[0];i++) is[prime[i]]=true;
}
int vis[maxn];
VI V[maxn];
int a[maxn];
int ans;
int st,en;

int head1[maxn];
struct edge
{
    int to,next;
}e[maxm];   //
int tol1=0;
void add(int u,int v)
{
    e[++tol1].to=v,e[tol1].next=head1[u],head1[u]=tol1;
}

void dfs1(int u)
{
    V[ans].pb(u);
    vis[u]=1;
    for(int i=head1[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(vis[v]) continue;
        dfs1(v);
    }
}

int main()
{
    init();
    get();
    int n;
    scanf("%d",&n);
    st=0,en=n+1;
    rep(i,1,n+1)
    {
        scanf("%d",&a[i]);
        if(a[i]&1) addedge(st,i,2);
        else addedge(i,en,2);
    }
    if(n&1)
    {
        return 0*puts("Impossible");
    }
    rep(i,1,n+1)
    {
        rep(j,i+1,n+1)
        {
            if((a[i]&1)&&(a[j]%2==0))
            {
                if(is[a[i]+a[j]])
                    addedge(i,j,1);
            }
            if((a[i]%2==0)&&(a[j]&1))
            {
                if(is[a[i]+a[j]])
                    addedge(j,i,1);
            }
        }
    }
    if(dinic(st,en)==n)
    {
        ans=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<tol;i+=2)
        {
            if(edge[i].cap==1)
            {
                add(edge[i].to,edge[i].from),add(edge[i].from,edge[i].to);
            }
        }
        memset(vis,0,sizeof(vis));
        rep(i,1,n+1)
        {
            if(!vis[i]) ans++,dfs1(i);
        }
        printf("%d
",ans);
        rep(i,1,ans+1)
        {
            printf("%d",V[i].size());
            rep(j,0,V[i].size()) printf(" %d",V[i][j]);
            puts("");
        }
    }
    else puts("Impossible");
    return 0;
}
原文地址:https://www.cnblogs.com/tarjan/p/6681022.html