1. 程式人生 > >[網路流24題]魔術球問題

[網路流24題]魔術球問題

題目描述

«問題描述:

假設有n根柱子,現要按下述規則在這n根柱子中依次放入編號為1,2,3,...的球。

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

(2)在同一根柱子中,任何2個相鄰球的編號之和為完全平方數。

試設計一個演算法,計算出在n根柱子上最多能放多少個球。例如,在4 根柱子上最多可放11 個球。

«程式設計任務:

對於給定的n,計算在n根柱子上最多能放多少個球。

輸入輸出格式

輸入格式:

 

第1 行有1個正整數n,表示柱子數。

 

輸出格式:

 

程式執行結束時,將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 }