假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2 ,3,… 的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何 2 个相邻球的编号之和为彻底平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多放 11 个球。
对于给定的 n,计算在 n 根柱子上最多能放多少个球。ios
假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2 ,3,… 的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何 2 个相邻球的编号之和为彻底平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多放 11 个球。
对于给定的 n,计算在 n 根柱子上最多能放多少个球。ios
输入文件第 1 行有 1 个正整数 n(1<n<60),表示柱子数。算法
输出 n 根柱子上最多能放的球数。网络
【样例说明】
最多能放 11 个球,下面 4 行,每行是一根柱子上的球的编号。
1 8
2 7 9
3 6 10
4 5 11设计
【思考如下输出样式】
将 n 根柱子上最多能放的球数以及相应的放置方案输出到文件中。
文件的第一行是球数。接下来的 n 行,每行是一根柱子上的球的编号。rest
首先能够想到这道题的策略确定是向上枚举球的数量而后判断····code
建图方法是:若是对于i<j有i+j为一个彻底平方数,链接一条有向边(i,j)。该图是有向无环图,求最小路径覆盖。若是恰好知足最小路径覆盖数等于N,那么A是一个可行解,在全部可行解中找到最大的A,即为最优解。最小路径覆盖相关知识点以下:blog
有向无环图最小不相交路径覆盖ip
定义:用最少的不相交路径覆盖全部顶点。
定理:把原图中的每一个点V拆成Vx和Vy,若是有一条有向边A->B,那么就加边Ax-By。这样就获得了一个二分图,最小路径覆盖=原图的节点数-新图最大匹配。
简单证实:一开始每一个点都独立的为一条路径,总共有n条不相交路径。咱们每次在二分图里加一条边就至关于把两条路径合成了一条路径,由于路径之间不能有公共点,因此加的边之间也不能有公共点,这就是匹配的定义。因此有:最小路径覆盖=原图的节点数-新图最大匹配。
所以每次枚举新的点加直接和以前的点枚加边便可···令外每次不用从新在图上跑网络流,记录一个group表示柱子数,和枚举的点数一块儿加减,而后用group减去新跑的流便可,这样就至关于枚举的点数减去在新图上彻底新跑出的流(看不懂的看代码就能够了),即为最小路径覆盖
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int inf=1e+9; const int N=100005; int src=0,des=10000; int group,num,n; int first[N],next[N*2],go[N*2],rest[N*2],tot=1,lev[N],cur[N]; inline void comb(int a,int b,int c) { next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c; next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0; } inline bool bfs() { for(int i=src;i<=des;i++) cur[i]=first[i],lev[i]=-1; static int que[N],tail,u,v; que[tail=1]=src; lev[src]=0; for(int head=1;head<=tail;head++) { u=que[head]; for(int e=first[u];e;e=next[e]) { if(lev[v=go[e]]==-1&&rest[e]) { lev[v]=lev[u]+1; que[++tail]=v; if(v==des) return true; } } } return false; } inline int dinic(int u,int flow) { if(u==des) return flow; int res=0,delta,v; for(int &e=cur[u];e;e=next[e]) { if(lev[v=go[e]]>lev[u]&&rest[e]) { delta=dinic(v,min(flow-res,rest[e])); if(delta) { rest[e]-=delta; rest[e^1]+=delta; res+=delta; if(res==flow) break; } } } if(flow!=res) lev[u]=-1; return res; } inline void maxflow() { while(bfs()) group-=dinic(src,inf); } int main() { //freopen("a.in","r",stdin); scanf("%d",&n); while(true) { group++,num++; for(int i=1;i<num;i++) if(sqrt(i+num)==(int)sqrt(i+num)) comb(i,num+5000,1); comb(num+5000,des,1); comb(src,num,1); maxflow(); if(group>n) break; } cout<<num-1<<endl; return 0; }