LibreOJ 6003 魔术球 (最大流)

题解:每次加入两个点,对于和为平方数的两个值所对应的点建边,反正网络流可以跑残量网络,所以就没有什么关系了……

代码如下:

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;

int head[100010],next[100010],w[100010],v[100010],deep[100010];
int s,t,cnt;


void init()
{
    cnt=-1;
    memset(head,-1,sizeof(head));
    memset(next,-1,sizeof(next));
}

void add(int from,int to,int cost)
{
    cnt++;
    next[cnt]=head[from];
    w[cnt]=cost;
    v[cnt]=to;
    head[from]=cnt;
}

void add_edge(int from,int to,int cost)
{
    add(from,to,cost);
    add(to,from,0);
}

int bfs(int s,int t)
{
    queue<int> q;
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u]; i!=-1; i=next[i])
        {
            if(!deep[v[i]]&&w[i]>0)
            {
                deep[v[i]]=deep[u]+1;
                q.push(v[i]);
            }
        }
    }
    if(!deep[t])
    {
        return 0;
    }
    return 1;
}

int dfs(int u,int t,int dist)
{
    if(u==t)
    {
        return dist;
    }
    for(int i=head[u]; i!=-1; i=next[i])
    {
        if(w[i]&&(deep[u]+1==deep[v[i]]))
        {
            int di=dfs(v[i],t,min(w[i],dist));
            if(di>0)
            {
                w[i]-=di;
                w[i^1]=di;
                return di;
            }
        }
    }
    return 0;
}

int dinic(int s,int t)
{
    int ans=0;
    while(bfs(s,t))
    {
        while(int d=dfs(s,t,inf))
        {
            ans+=d;
        }
    }
    return ans;                //
}

int id[11110],wid[11110],vis[11110];
void solve(int x,int &f)
{
    int loc=wid[x];
    vis[x]=1;
    for(int i=head[loc]; i!=-1; i=next[i])
    {
        if(w[i]==1&&v[i]!=t)
        {
            solve(v[i]/2,f);
        }
    }
    if(f==1)
    {
        f=0;
    }
    else
    {
        putchar(' ');
    }
    printf("%d",x);
}

int main()
{
    init();
    int n;
    scanf("%d",&n);
    s=0;
    t=11110;
    int i,tmp=2,ans=0,tmp2=0;

    for(i=1; i-ans<=n+1; i++)
    {
        id[i]=tmp++;
        wid[i]=tmp++;
        add_edge(s,id[i],1);
        add_edge(wid[i],t,1);
        for(int j=1; j<i; j++)
        {
            int tmp1=sqrt(i+j);
            if(tmp1*tmp1==i+j)
            {
                add_edge(id[j],wid[i],1);
            }
        }
        ans+=dinic(s,t);
    }
    tmp2=i-2;
    printf("%d\n",tmp2);
    for(int i=head[t]; i!=-1; i=next[i])
    {
        if(w[i]==1&&!vis[v[i]/2])
        {
            int f=1;
            solve(v[i]/2,f);
            puts("");
        }
    }
    for(int i=1; i<=tmp2; i++)
    {
        if(!vis[i])
        {
            printf("%d\n",i);
        }
    }
}

 

posted @ 2018-03-16 19:32  Styx-ferryman  阅读(250)  评论(0编辑  收藏  举报