首页 > 代码库 > 【网络流24题】魔术球问题

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

Description

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可 放11个球。
′编程任务:
对于给定的n,计算在 n根柱子上最多能放多少个球。

Input

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

Output

第一行是球数。

Sample Input

4

Sample Output

11

Hint

样例方案如下
1 8
2 7 9
3 6 10
4 5 11
每一行表示一个柱子上的球
n<=60 保证答案小于1600

正解:最大流。

考虑把球拆成两个点,动态连边,在残量网络上直接跑最大流。一个点连源点,一个点连汇点,在这个球之前的球,如果相加等于完全平方数,那么这个球连向汇点的点与之前那个球连向源点的点相连。从前往后枚举球,如果当前总球数-最大流>n,那么就不合法了。输出当前的前一个球即可。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <complex>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cmath>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <set>
14 #define inf (1<<30)
15 #define eps 1e-9
16 #define il inline
17 #define RG register
18 #define ll long long
19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
20 
21 using namespace std;
22 
23 struct edge{ int nt,to,flow,cap; }g[1000010];
24 
25 int head[3210],d[3210],q[3210],n,S,T,flow,num=1;
26 
27 il int gi(){
28     RG int x=0,q=1; RG char ch=getchar(); while ((ch<0 || ch>9) && ch!=-) ch=getchar();
29     if (ch==-) q=-1,ch=getchar(); while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); return q*x;
30 }
31 
32 il void insert(RG int from,RG int to,RG int cap){ g[++num]=(edge){head[from],to,0,cap},head[from]=num; return; }
33 
34 il int bfs(RG int S,RG int T){
35     memset(d,0,sizeof(d)); RG int h=0,t=1; q[t]=S,d[S]=1;
36     while (h<t){
37     RG int x=q[++h];
38     for (RG int i=head[x];i;i=g[i].nt){
39         RG int v=g[i].to;
40         if (!d[v] && g[i].cap>g[i].flow){
41         q[++t]=v,d[v]=d[x]+1;
42         if (v==T) return 1;
43         }
44     }
45     }
46     return 0;
47 }
48 
49 il int dfs(RG int x,RG int T,RG int a){
50     if (x==T || !a) return a; RG int f,flow=0;
51     for (RG int i=head[x];i;i=g[i].nt){
52     RG int v=g[i].to;
53     if (d[v]==d[x]+1 && g[i].cap>g[i].flow){
54         f=dfs(v,T,min(a,g[i].cap-g[i].flow));
55         g[i].flow+=f,g[i^1].flow-=f;
56         flow+=f,a-=f; if (!a) return flow;
57     }
58     }
59     if (!flow) d[x]=-1; return flow;
60 }
61 
62 il int maxflow(RG int S,RG int T){ while (bfs(S,T)) flow+=dfs(S,T,inf); return flow; }
63 
64 il void work(){
65     n=gi(),S=3201,T=3202;
66     for (RG int ans=1;ans<=1600;++ans){
67     insert(S,ans,1),insert(ans,S,0);
68     for (RG int i=1;i<ans;++i)
69         if (ans+i-(int)sqrt(ans+i)*(int)sqrt(ans+i)<eps)
70         insert(i,ans+1600,1),insert(ans+1600,i,0);
71     insert(ans+1600,T,1),insert(T,ans+1600,0);
72     if (ans-maxflow(S,T)>n){ printf("%d\n",ans-1); return; }
73     }
74     return;
75 }
76 
77 int main(){
78     File("ball");
79     work();
80     return 0;
81 }

 

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