【网络流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 }