假設有 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; }