[Codeforces 510E] Fox And Dinner (网络流+分组建图)

Codeforces - 510E

有 N只狐妖,其中年龄加起来为质数的可以坐在一次
求一种方案,使所有人都坐成若干个环


注意到每个人的年龄都大于等于2
这意味着所有的质数都是奇数
相邻两个一个是奇数,一个是偶数
所以整张图是一个二分图

然后跑网络流
源点对奇数点连容量为 2的边
偶数点对汇点连容量为 2的边
中间奇数点对偶数点连容量为 1的边
表示每个点至多有两个邻居
最后检查一下是否满流就行

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
#include <complex>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n----------")
#define PRI(x) cout << #x << ":" << x << endl;

const int maxn=200+10, maxm=4e4+10, maxp=2e4+10;
struct Graph
{
    int ndn, edn, last[maxn];
    int u[maxm*2], v[maxm*2], c[maxm*2], nxt[maxm*2];
    void init(int _n){ndn=_n; edn=0; MST(last,-1);}
    void adde(int _u, int _v, int _c)
    {
        u[edn]=_u; v[edn]=_v; c[edn]=_c;
        nxt[edn]=last[_u];
        last[_u]=edn++;
    }
};
struct Dinic
{
    Graph *G;
    int S, T, dist[maxn], cur[maxn];
    int bfs();
    int dfs(int,int);
    int solve(Graph*, int, int);
};

int N, A[maxn];
bool sieve[maxp];
bool vis[maxn];
vector<int> to[maxn];
vector<vector<int>> ans;
Graph G;
Dinic D;

void gen(int);
void dfs(int,vector<int>&);

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif

    for(int i=2; i<maxp; i++) if(!sieve[i]) for(int j=i*i; j<maxp; j+=i)
        sieve[j] = 1;

    int S,T;
    while(~scanf("%d", &N))
    {
        S=N+1, T=N+2;
        G.init(N+2);
        for(int i=1; i<=N; i++) scanf("%d", &A[i]);
        int sum = 0;
        for(int i=1; i<=N; i++)
        {
            if(A[i]&1) G.adde(S,i,2), G.adde(i,S,0);
            else G.adde(i,T,2), G.adde(T,i,0), sum+=2;
        }
        int eno = G.edn;
        for(int e0=G.last[S]; ~e0; e0=G.nxt[e0])
            for(int e1=G.last[T]; ~e1; e1=G.nxt[e1])
            {
                int u=G.v[e0], v=G.v[e1];
                if(!sieve[A[u]+A[v]])
                {
                    G.adde(u,v,1);
                    G.adde(v,u,0);
                }
            }

        vector<int> res;
        if(D.solve(&G,S,T)!=sum) puts("Impossible");
        else
        {
            CLR(vis);
            ans.clear();
            for(int i=1; i<=N; i++) to[i].clear();
            for(int e=eno; e<G.edn; e+=2) if(!G.c[e])
            {
                to[G.u[e]].push_back(G.v[e]);
                to[G.v[e]].push_back(G.u[e]);
            }
            for(int i=1; i<=N; i++) if(!vis[i])
            {
                res.clear();
                dfs(i, res);
                ans.push_back(res);
            }
            cout << ans.size() << "\n";
            for(auto now:ans)
            {
                cout << now.size();
                for(auto ct:now) cout << " " << ct;
                puts(""); 
            }
        }

    }
    return 0;
}

void dfs(int u, vector<int> &ans)
{
    vis[u] = 1;
    ans.push_back(u);
    for(auto v:to[u]) if(!vis[v])
    {
        dfs(v, ans);
        return;
    }
}

int Dinic::solve(Graph *g, int s, int t)
{
    G=g; S=s; T=t;
    int res = 0;
    while(bfs())
    {
        for(int i=1; i<=G->ndn; i++) cur[i] = G->last[i];
        res += dfs(S, 1e9);
    }
    return res;
}

int Dinic::bfs()
{
    MST(dist,-1);
    dist[S] = 0;
    queue<int> que;
    que.push(S);

    while(que.size())
    {
        int u=que.front(); que.pop();
        for(int e=G->last[u]; ~e; e=G->nxt[e]) 
        {
            int v=G->v[e];
            if(dist[v]==-1 && G->c[e]>0)
            {
                dist[v] = dist[u]+1;
                que.push(v);
            }
        }
    }

    return ~dist[T];
}

int Dinic::dfs(int u, int tmin)
{
    if(u==T || tmin==0) return tmin;
    int nflw=0, f;
    for(int &e=cur[u]; ~e; e=G->nxt[e])
    {
        int v=G->v[e];
        if(dist[u]+1==dist[v] && (f=dfs(v,min(tmin, G->c[e]))) > 0)
        {
            G->c[e] -= f;
            G->c[e^1] += f;
            nflw += f;
            tmin -= f;
            if(tmin==0) break;
        }
    }
    return nflw;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值