«問題描述:算法
假設有n根柱子,現要按下述規則在這n根柱子中依次放入編號爲1,2,3,...的球。編程
(1)每次只能在某根柱子的最上面放球。網絡
(2)在同一根柱子中,任何2個相鄰球的編號之和爲徹底平方數。spa
試設計一個算法,計算出在n根柱子上最多能放多少個球。例如,在4 根柱子上最多可放11 個球。設計
«編程任務:code
對於給定的n,計算在n根柱子上最多能放多少個球。blog
輸入格式:string
第1 行有1個正整數n,表示柱子數。it
輸出格式:io
程序運行結束時,將n 根柱子上最多能放的球數以及相應的放置方案輸出。文件的第一行是球數。接下來的n行,每行是一根柱子上的球的編號。
能夠肯定的是必定要邊枚舉當前要放的球邊跑最大流
兩個加起來是徹底平方的球之間必定是要連邊的。
因爲放的順序從小到大,因此連邊的方向必定是從當前球向已放球
邊的容量均爲1,每次在原網絡上建邊跑最大流,
若是存在最大流,證實當前球能夠放在另外一球上面
不然就要自立門戶了。。。
若是你單純地按上面的描述建邊,會發現出現了一點小問題。。。
這時候須要用到一個小技巧————拆點
將一個點拆成入點和出點,入點和s,出點和t連邊,入點向出點連邊
完成!
1 #include<cmath> 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 int n,m,cnt,tot,tp; 8 int st,ed,ans,num; 9 int head[200005]; 10 int cur[200005]; 11 int dis[200005]; 12 int pre[200005]; 13 bool usd[200005]; 14 int pr[200005]; 15 struct Edge{ 16 int fr; 17 int to; 18 int flw; 19 int nxt; 20 }edge[8888888]; 21 void init(){ 22 memset(head,-1,sizeof(head)); 23 } 24 void addedge(int u,int v,int f){ 25 edge[cnt].fr=u; 26 edge[cnt].to=v; 27 edge[cnt].flw=f; 28 edge[cnt].nxt=head[u]; 29 head[u]=cnt++; 30 edge[cnt].fr=v; 31 edge[cnt].to=u; 32 edge[cnt].nxt=head[v]; 33 head[v]=cnt++; 34 } 35 int bfs(int ban){ 36 queue<int>que; 37 memset(dis,0x3f,sizeof(dis)); 38 que.push(st);dis[st]=1; 39 while(!que.empty()){ 40 int u=que.front(); 41 que.pop(); 42 for(int i=head[u];i!=-1;i=edge[i].nxt){ 43 int v=edge[i].to; 44 if(ban==v)continue; 45 if(!edge[i].flw)continue; 46 if(dis[v]==0x3f3f3f3f){ 47 dis[v]=dis[u]+1; 48 que.push(v); 49 } 50 } 51 } 52 return dis[ed]!=0x3f3f3f3f; 53 } 54 int dfs(int u,int flw){ 55 if(u==ed)return flw; 56 int All=0,tmp; 57 for(int i=cur[u];i!=-1;i=edge[i].nxt){ 58 if(!edge[i].flw)continue; 59 int v=edge[i].to;cur[u]=i; 60 if(dis[v]!=dis[u]+1)continue; 61 if((tmp=dfs(v,min(flw,edge[i].flw)))>0){ 62 pre[v]=u; 63 edge[i].flw-=tmp; 64 edge[i^1].flw+=tmp; 65 flw-=tmp,All+=tmp; 66 if(!flw)break; 67 } 68 } 69 return All; 70 } 71 int dinic(int ban){ 72 int ret=0; 73 while(bfs(ban)){ 74 memcpy(cur,head,sizeof(cur)); 75 ret+=dfs(st,0x3f3f3f3f); 76 } 77 return ret; 78 } 79 int main(){ 80 init();ed=200000; 81 scanf("%d",&n); 82 while(true){ 83 ans++; 84 addedge(st,ans*2-1,1); 85 addedge(ans*2,ed,1); 86 for(int i=1;i<ans;i++){ 87 int a=sqrt(ans+i); 88 if(a*a!=ans+i)continue; 89 addedge(i*2-1,ans*2,1); 90 } 91 num+=1-dinic(-1); 92 if(num>n){ 93 printf("%d\n",ans-1); 94 dinic(ans*2); 95 for(int i=1;i<ans;i++){ 96 usd[(pre[2*i]+1)/2]=true; 97 } 98 for(int i=1;i<ans;i++){ 99 if(!usd[i]){ 100 int now=i;tp=0; 101 while(now){ 102 pr[++tp]=now; 103 now=(pre[now*2]+1)/2; 104 } 105 for(int i=tp;i>=1;i--){ 106 printf("%d",pr[i]); 107 if(i!=1)printf(" "); 108 } 109 printf("\n"); 110 } 111 } 112 break; 113 } 114 } 115 return 0; 116 }