当前位置: 首页 > 工具软件 > Dinner > 使用案例 >

Codeforces 510E Fox and Dinner 题解

丌官高远
2023-12-01

题意简述

给定 n ( < = 200 ) n(<=200) n(<=200)个数 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an 2 < = a i < = 10000 2<=a_i<=10000 2<=ai<=10000,把这 n n n个数分成几组,使得每组中能排出一个序列,并且相邻两个和都是质数。输出方案。

思路

注意: 2 < = a i < = 10000 2<=a_i<=10000 2<=ai<=10000。所以,我们将 a a a按奇偶分类,只有奇数能和偶数在一块,奇数和奇数不能一块,偶数和偶数不能一块。所以我们把它们按奇偶分类,又注意到 n < = 200 n<=200 n<=200,考虑网络流。

  • 对于偶数的 a i a_i ai ( S − > a i , 2 ) (S->a_i,2) (S>ai,2)
  • 对于奇数的 a i a_i ai ( a i − > T , 2 ) (a_i->T,2) (ai>T,2)
  • 对于 a i + a j = p r i m e a_i+a_j=prime ai+aj=prime,且 a i a_i ai是偶数, a j a_j aj是奇数: ( a i − > a j , 1 ) (a_i->a_j,1) (ai>aj,1)

跑一遍最大流。如果最大流 = n =n =n D F S DFS DFS求出分组。否则就不可能。

预处理质数, O ( 10000 + n 2 + C ) O(10000+n^2+C) O(10000+n2+C)解决(其中 C C C是网络流的复杂度,又被称为玄学常数)

10.24upd 关于建图的具体思路 建图是一个很考验思维能力的过程。

首先我们注意到,每个数最多有两个数相邻,所以这个数和源点/汇点的连边容量为 2 2 2,就代表它最多能通过两条边。而 D F S DFS DFS的时候,就是通过连接的两条边判断相邻,然后判断顺序的。

然后,考虑到相邻两个数的和必须是质数,所以,不是所有的边都能流过去,必须只有质数才能流过去。所以我们判断两个数的和是否为质数,如果是质数那么就连一条容量为 1 1 1的流过去。

我个人认为,虽然网络流建图就是个毒瘤,但是这个题还比较容易能理解。

代码:

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
    #define N 322
    #define M 24444
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define Tra(i,u) for(int i=Nt.Start(u),__v=Nt.To(i);~i;i=Nt.Next(i),__v=Nt.To(i))
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)
    class Graph
    {
        public:
            int EdgeCount;
            int head[M];
            struct Edge
            {
                int To,Label;
                int Next;
            }Ed[2666666];
            void clear()
            {
                MEM(head,-1);
                MEM(Ed,-1);
                EdgeCount=-1;
            }
            void AddEdge(int u,int v,int w)
            {
                ++EdgeCount;
                Ed[EdgeCount]=(Edge){v,w,head[u]};
                head[u]=EdgeCount;
            }
            void AddFlow(int u,int v,int w)
            {
                AddEdge(u,v,w);
                AddEdge(v,u,0);
            }
            int Start(int i){return head[i];}
            int To(int i){return Ed[i].To;}
            int Label(int i){return Ed[i].Label;}
            int Next(int i){return Ed[i].Next;}
    
            int Source,Sink;
            int deep[N];
            queue<int>Q,EmptyQ;
            bool BFS()
            {
                Q=EmptyQ;
                FK(deep);
    
                Q.push(Source);
                deep[Source]=1;
                do
                {
                    int u=Q.front();Q.pop();
                    for(int i=head[u];~i;i=Ed[i].Next)
                    {
                        int v=Ed[i].To;
                        if (deep[v]==0 and Ed[i].Label>0)
                        {
                            deep[v]=deep[u]+1;
                            Q.push(v);
                        }
                    }
                }while(!Q.empty());
    
                if (deep[Sink]==0) return 0;
                return 1;
            }
            int DFS(int u,int MinFlow)
            {
                if (u==Sink) return MinFlow;
                for(int i=head[u];~i;i=Ed[i].Next)
                {
                    int v=Ed[i].To;
                    if (deep[v]==deep[u]+1 and Ed[i].Label!=0)
                    {
                        int d=DFS(v,min(MinFlow,Ed[i].Label));
                        if (d>0)
                        {
                            Ed[i].Label-=d;
                            Ed[i^1].Label+=d;
                            return d;
                        }
                    }
                }
                return 0;
            }
            int Dinic()
            {
                int ans=0;
                while(BFS())
                {
                    int d;
                    while(d=DFS(Source,0x3f3f3f3f))
                    {
                        ans+=d;
                    }
                }
                return ans;
            }
    }Nt;
    int n,a[N];
    void R1(int &x)
    {
        x=0;char c=getchar();int f=1;
        while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=(f==1)?x:-x;
    }
    void Input()
    {
        R1(n);
        F(i,1,n) R1(a[i]);
    }

    int primes[M],notp[M];
    void Init()
    {
        int &cnt=primes[0];
        int n=20000;
        notp[1]=1;
        F(i,2,n)
        {
            if (!notp[i]) primes[++cnt]=i;
            for(int j=1;i*primes[j]<=n and j<=cnt;++j)
            {
                int u=primes[j];
                notp[i*u]=true;
                if (i%u==0) break;
            }
        }
    }
    #define S Nt.Source
    #define T Nt.Sink
    vector<int> mp[M];
    bool vis[M];
    void DFS(int u,int tot)
    {
        mp[tot].push_back(u);
        vis[u]=1;
        Tra(i,u)
        {
            int v=__v;
            if (vis[v]==1) continue;
            if (v!=S and v!=T)
            {
                if (i%2==0 and Nt.Label(i)  ==0) DFS(v,tot);
                if (i%2==1 and Nt.Label(i^1)==0) DFS(v,tot);
            }
        }
    }
    void Soviet()
    {
        Init();
        Nt.clear();
        S=n+1,T=n+2;
        F(i,1,n)
        {
            if (a[i]%2==0)
            {
                Nt.AddFlow(S,i,2);
            }
            else
            {
                Nt.AddFlow(i,T,2);
            }
        }
        F(i,1,n) F(j,1,n)
        {
            if (a[i]%2==0 and a[j]%2==1 and !notp[a[i]+a[j]])
            {
                Nt.AddFlow(i,j,1);
            }
        }
        int flow=Nt.Dinic();
        if (flow==n)
        {
            FK(vis);
            int tot=0;
            F(i,1,n)
            {
                if (vis[i]==0) 
                {
                    DFS(i,++tot);
                }
            }
            printf("%d\n",tot);
            F(i,1,tot)
            {
                printf("%d",mp[i].size());
                F(j,0,(int)mp[i].size()-1)
                {
                    printf(" %d",mp[i][j]);
                }
                putchar('\n');
            }
        }
        else
        {
            puts("Impossible");
        }
    }

    #define Flan void
    Flan IsMyWife()
    {
        Input();
        Soviet();
    }
}
int main()
{
    Flandre_Scarlet::IsMyWife();
    getchar();getchar();
    return 0;
}
 类似资料: