CF 510E Fox And Dinner(最大流)

CF 510E Fox And Dinner

n个狐狸围桌吃饭 每个狐狸身上自带一个值fi 现在要使得相邻的两个狐狸Fi Fi+1的和为质数(F1与Fn相邻)

问可以把这些狐狸安排到几个桌子 如果可以给出每个桌子上狐狸安排的顺序


因为每个每个Fi的值都是大于2的 所以两个值相加要为质数  这个质数肯定是个奇数  所以要满足奇数+偶数

所以把初始的n个值分为两部分 一个部分为奇数部分 一个为偶数部分

且每个奇数与两个偶数相邻 每个偶数与两个奇数相邻

虚拟一个源点 汇点 源点与偶数之间建边 权值为2  奇数与汇点之间建边 权值为2

满足相加为质数的偶数与奇数之间建边 权值为1  跑最大流 看答案是否为n

然后需要去存储答案  如果奇数与偶数之间有流  则说明这条边是满足情况的 从一个点出发找出一条路径

即是一个桌子的情况

注意这道题建的是有向边

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>

#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 410
#define MAXM 100010
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)

using namespace std;

int Read()
{
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    int x = 0;
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

void Print(int a)
{
     if(a>9)
         Print(a/10);
     putchar(a%10+'0');
}

struct Edge
{
    int from,to,cap,flow;
    bool operator <(const Edge e) const
    {
        if(e.from!=from)  return from<e.from;
        else return to<e.to;
    }
    Edge() {}
    Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow) {}
};

struct Dinic
{
    vector<Edge> edges;
    vector<int> G[MAXN];
    bool vis[MAXN];//BFS使用
    int d[MAXN];   //从起点到i的距离
    int cur[MAXN]; //当前弧下标
    int n,m,s,t,maxflow;   //节点数 边数(包括反向弧) 源点编号和弧点编号

    void init(int n)
    {
        this->n=n;
        for(int i=0;i<=n;i++)
            G[i].clear();
        edges.clear();
    }

    void addedge(int from,int to,int cap)
    {
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));//当是无向图时,反向边容量也是cap,有向边时,反向边容量是0
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool bfs()
    {
        MEM(vis,0);
        MEM(d,-1);
        queue<int> q;
        q.push(s);
        d[s]=maxflow=0;
        vis[s]=1;
        while(!q.empty())
        {
            int u=q.front(); q.pop();
            int sz=G[u].size();
            for(int i=0;i<sz;i++)
            {
                Edge e=edges[G[u][i]];
                if(!vis[e.to]&&e.cap>e.flow)
                {
                    d[e.to]=d[u]+1;
                    vis[e.to]=1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int dfs(int u,int a)
    {
        if(u==t||a==0)  return a;
        int sz=G[u].size();
        int flow=0,f;
        for(int &i=cur[u];i<sz;i++)
        {
            Edge &e=edges[G[u][i]];
            if(d[u]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edges[G[u][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)  break;
            }
        }
        return flow;
    }

    int Maxflow(int s,int t)
    {
        this->s=s; this->t=t;
        int flow=0;
        while(bfs())
        {
            MEM(cur,0);
            flow+=dfs(s,INF);
        }
        return flow;
    }

}Dic;

bool notprime[50010];//值为0表示素数  为1表示非素数
void isprime()
{
    MEM(notprime,0);
    notprime[0]=notprime[1]=1;
    for(int i=2;i<50000;i++)
    {
        if(!notprime[i])
        {
            if(i>50000/i) continue;
            for(int j=i*i;j<50000;j+=i)
                notprime[j]=1;
        }
    }
}

bool isPrime(int n)
{
    for(int i=2;i*i<=n;i++)
        if(n%i==0) return 0;
    return 1;
}

int vis[MAXN];
int a[MAXN];
vector<int> g[MAXN];

int main()
{
//    fread;
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    Dic.init(n+1);
    int s=n,t=n+1;
    for(int i=0;i<n;i++)
    {
        if(a[i]%2==0)
            Dic.addedge(s,i,2);
        else Dic.addedge(i,t,2);
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i]%2==0&&a[j]%2!=0&&isPrime(a[i]+a[j]))
                Dic.addedge(i,j,1);
        }
    }
    int res=Dic.Maxflow(s,t);
    if(res!=n)
    {
        puts("Impossible");
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<Dic.G[i].size();j++)
        {
            int index=Dic.G[i][j];
            if(Dic.edges[index].flow>0&&Dic.edges[index].to<n)
            {
                g[i].push_back(Dic.edges[index].to);
                g[Dic.edges[index].to].push_back(i);
            }
        }
    }
    vector< vector<int> > path;
    for(int i=0;i<n;i++)
    {
        if(vis[i])
            continue;
        vector<int> current;
        int j=i;
        while(1)
        {
            current.push_back(j);
            vis[j]=1;
            int nj=-1;
            for(int k=0;k<g[j].size();k++)
            {
                if(!vis[g[j][k]])
                {
                    nj=g[j][k];
                    break;
                }
            }
            if(nj==-1)
            {
                break;
            }
            j=nj;
        }
        path.push_back(current);
    }
    printf("%d\n",path.size());
    for(int i=0;i<path.size();i++)
    {
        printf("%d",path[i].size());
        for(int j=0;j<path[i].size();j++)
            printf(" %d",path[i][j]+1);
        printf("\n");
    }
    return 0;
}


//int main()
//{
    fread;
//    isprime();
//    int n;
//    scanf("%d",&n);
    while(scanf("%d",&n)!=EOF)
    {
//        for(int i=1;i<=n;i++)
//            scanf("%d",&a[i]);
        int n1=0,n2=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]&1)
            {
                a1[++n1]=a[i];
                num1[n1]=i;
            }
            else
            {
                a2[++n2]=a[i];
                num2[n2]=i;
            }
        }
        if(n1!=n2)
        {
            puts("Impossible");
            continue;
        }
        int s=0,t=n+1;
        Dic.init(t);
        for(int i=1;i<=n1;i++)
            Dic.addedge(s,i,2);
        for(int i=1;i<=n2;i++)
            Dic.addedge(i+n1,t,2);
//        cout<<"n "<<n<<"  "<<n1+n2<<endl;
        for(int i=1;i<=n1;i++)
            for(int j=1;j<=n2;j++)
            {
                if(!notprime[a1[i]+a2[j]])
                    Dic.addedge(i,j+n1,1);
            }
        int mxflow=Dic.Maxflow(s,t);
        if(mxflow!=n)
        {
            puts("Impossible");
            continue;
        }
//        int s=0,t=n+1;
//        Dic.init(t);
//        for(int i=1;i<=n;i++)
//        {
//            if(a[i]%2==0)
//                Dic.addedge(s,i,2);
//            else Dic.addedge(i,t,2);
//        }
//        for(int i=1;i<=n;i++)
//            for(int j=1;j<=n;j++)
//            {
//                if(a[i]%2==0&&a[j]%2!=0&&!notprime[a[i]+a[j]])
//                    Dic.addedge(i,j,1);
//            }
//        int res=Dic.Maxflow(s,t);
//        if(res!=n)
//        {
//            puts("Impossible");
//            return 0;
//        }
        for(int i=0;i<=t;i++)
            g[i].clear();
//        for(int i=1;i<=n;i++)
//        {
//            for(int j=0;j<Dic.G[i].size();j++)
//            {
//                int index=Dic.G[i][j];
//                if(Dic.edges[index].flow>0&&Dic.edges[index].to<=n)
//                {
//                    g[i].push_back(Dic.edges[index].to);
//                    g[Dic.edges[index].to].push_back(i);
//                }
//            }
//        }
//        vector< vector<int> > path;
//        MEM(vis,0);
//        for(int i=1;i<=n;i++)
//        {
//            if(vis[i]) continue;
//            vector<int> current;
//            int j=i;
//            while(1)
//            {
//                current.push_back(j);
//                vis[j]=1;
//                int nj=-1;
//                for(int k=0;k<g[j].size();k++)
//                {
//                    if(!vis[g[j][k]])
//                    {
//                        nj=g[j][k];
//                        break;
//                    }
//                }
//                if(nj==-1)
//                {
//                    break;
//                }
//                j=nj;
//            }
//            path.push_back(current);
//        }
//        printf("%d\n",path.size());
//        for(int i=0;i<path.size();i++)
//        {
//            printf("%d",path[i].size());
//            for(int j=0;j<path[i].size();j++)
//                printf(" %d",path[i][j]);
//            puts("");
//        }
        int tot=0;
        for(int i=1;i<=n1;i++)
        {
            int sz=Dic.G[i].size();
            for(int j=0;j<sz;j++)
            {
                int x=Dic.G[i][j];
                if(Dic.edges[x].flow>0)
                {
                    ans[++tot][1]=num1[i];
                    ans[tot][2]=num2[Dic.edges[x].to-n1];
                }
            }
        }
        int m=0;
        MEM(vis,0);
        MEM(st,0);
        for(int i=1;i<=tot;i++)
        {
            if(!vis[i])
            {
                vis[i]=1;
                st[++m][1]=ans[i][1];
                st[m][2]=ans[i][2];
                int st_size=2;
                while(st[m][1]!=st[m][st_size])
                {
                    for(int i=1;i<=tot;i++)
                    {
                        if(!vis[i])
                        {
                            if(ans[i][1]==st[m][st_size])
                            {
                                st[m][++st_size]=ans[i][2];
                                vis[i]=1;
                                break;
                            }
                            if(ans[i][2]==st[m][st_size])
                            {
                                st[m][++st_size]=ans[i][1];
                                vis[i]=1;
                                break;
                            }
                        }
                    }
                }
                st[m][0]=st_size-1;
            }
        }
        printf("%d\n",m);
        for(int i=1;i<=m;i++)
        {
//            cout<<"i  "<<i<<endl;
            printf("%d",st[i][0]);
            for(int j=1;j<=st[i][0];j++)
                printf(" %d",st[i][j]);
            puts("");
        }
    }
//
//    return 0;
//}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值