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

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

 

 

问题转化为最小路径覆盖的逆问题,从1开始枚举答案,跑最大流,计算出最小覆盖。
当最小覆盖>n时退出。
这里的实现有一个技巧:
在每次枚举时并不需要重新连边,只需要加上这次枚举的答案所连的边,然后在上次的残余网络上跑最大流就可以了。
 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 using namespace std;
15 struct data{
16   int nex,to,w;
17 }e[700000];
18 int head[10100],edge=-1,lev[10100];
19 void add(int from,int to,int w){
20   e[++edge].nex=head[from];
21   e[edge].to=to;
22   e[edge].w=w;
23   head[from]=edge;
24 }
25 inline bool bfs(int s,int t){
26   queue<int>q;
27   memset(lev,0,sizeof(lev));
28   lev[s]=1;
29   q.push(s);
30   while(!q.empty()){
31     int u=q.front();
32     q.pop();
33     for(int i=head[u];i!=-1;i=e[i].nex)
34       if(!lev[e[i].to] && e[i].w>0){
35     lev[e[i].to]=lev[u]+1;
36     if(e[i].to==t) return 1;
37     else q.push(e[i].to);
38       }
39   }
40   return 0;
41 }
42 int dfs(int s,int t,int k){
43   if(s==t) return k;
44   int rag=0;
45   for(int i=head[s];i!=-1;i=e[i].nex)
46     if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
47       int d=dfs(e[i].to,t,min(k-rag,e[i].w));
48       e[i].w-=d;
49       e[i^1].w+=d;
50       rag+=d;
51       if(rag==k) return rag;
52     }
53   return rag;
54 }
55 int dinic(int s,int t){
56   int flow=0;
57   while(bfs(s,t))flow+=dfs(s,t,1999999999);
58   return flow;
59 }
60 int main()
61 {
62   freopen("!.in","r",stdin);
63   freopen("!.out","w",stdout);
64   int n;scanf("%d",&n);
65   memset(head,-1,sizeof(head));
66   int num=0,ans=0,s=0,t=10010;
67   while(1){
68     num++,ans++;
69     for(int i=1;i<num;i++)
70       if(sqrt(i+num)==(int)(sqrt(i+num))) add(i,num+2000,1),add(num+2000,i,0);
71     add(s,num,1),add(num,s,0);add(num+2000,t,1),add(t,num+2000,0);
72     ans-=dinic(s,t);
73     if(ans>n) break;
74   }
75   printf("%d",num-1);
76   return 0;
77 }

 

 
posted @ 2017-03-24 21:21  嘘丶  阅读(196)  评论(0编辑  收藏  举报