【网络流24题】魔术球问题

Description

假设有 n根柱子,现要按下述规则在这 n根柱子中依次放入编号为 1,2,3,…的球。

(1)每次只能在某根柱子的最上面放球。

(2)在同一根柱子中,任何 2个相邻球的编号之和为完全平方数。

试设计一个算法,计算出在 n根柱子上最多能放多少个球。例如,在 4根柱子上最多可放 11个球。

对于给定的 n,计算在 n根柱子上最多能放多少个球。

Input

文件第 1行有 1个正整数 n,表示柱子数。

Output

程序运行结束时,将 n根柱子上最多能放的球数以及相应的放置方案输出。文件的第一行是球数。接下来的 n行,每行是一根柱子上的球的编号。

Sample Input

4

Sample Output

11
1 8
2 7 9
3 6 10
4 5 11

HINT

n<60
题解

网络流最大流
枚举答案s,在图中建节点1,2,….,s,并将每个节点拆成两个点,一个连接原点,一个连接汇点,对于每一个i< j,如果存在i+j是一个平方数,那么就将i与原点连接的点和j与汇点连接的点建边。每次求一遍最大流a,如果a-1==n,那么s-1即为所求解。

code
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define N 10010
#define inf 0x7fffffff
using namespace std;
struct node
{
    int next,to,s;
};
node Edge[N*20];
const int m=5000;
const int T=10000;
int n,ans,s,tot=1;
int head[N];
int h[N],que[N];
bool used[N];
int to[N];

void add(int x,int y,int z)
{
    Edge[++tot].next=head[x];
    Edge[tot].to=y;
    Edge[tot].s=z;
    head[x]=tot;
}

void ins(int x,int y)
{
    add(x,y,1),add(y,x,0);
}

bool bfs()
{
    queue<int>Q;
    memset(h,-1,sizeof(h));
    h[0]=0;
    Q.push(0);
    while(!Q.empty())
    {
        int now=Q.front();
        Q.pop();
        for(int i=head[now];i;i=Edge[i].next)
        {
            if(h[Edge[i].to]==-1&&Edge[i].s)
            {
                h[Edge[i].to]=h[now]+1;
                Q.push(Edge[i].to);
            }
        }
    }
    if(h[T]==-1)return false;
    return true;
}

int dfs(int u,int f)
{
    if(u==T)return f;
    int used=0;
    for(int i=head[u];i;i=Edge[i].next)
    {
        if(!Edge[i].s||h[Edge[i].to]!=h[u]+1)continue;
        int w=f-used;
        w=dfs(Edge[i].to,min(w,Edge[i].s));
        Edge[i].s-=w;
        Edge[i^1].s+=w;
        used+=w;
        if(used==f)return f;
    }
    if(!used)h[u]=-1;
    return used;
}

void dinic()
{
    while(bfs())
        ans-=dfs(0,inf);
}

void getans()
{
    for(int i=1;ifor(int j=head[i];j;j=Edge[j].next)
        {
            if(Edge[j].s)continue;
            to[i]=Edge[j].to-m;
            break;
        }
    }
    for(int i=1;iif(used[i])continue;
        int t=i;
        while(t!=-m)
        {
            printf("%d ",t);
            used[t]=true;
            t=to[t];
        }
        puts("");
    }
}

int main()
{
    cin>>n;
    for(;;)
    {
        ans++,s++;
        for(int i=1;iif(sqrt(i+s)==(int)sqrt(i+s))
                ins(i,s+m);
        ins(0,s),ins(s+m,T);
        dinic();
        if(ans>n)break;
    }
    printf("%d\n",s-1);
    getans();
    return 0;
}

你可能感兴趣的:(其它oj,图论,网络流)