【网络流24题】魔术球问题 二分答案+最小路径覆盖
Description
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。 (1)每次只能在某根柱子的最上面放球。 (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。 试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可 放11 个球。 编程任务: 对于给定的n,计算在n根柱子上最多能放多少个球。
Input
由文件input.txt提供输入数据。文件第1 行有1个正整数n(n<=55),表示柱子数。
Output
程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出到文件 output.txt中。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。
Sample Input
4
Sample Output
11 1 8 2 7 9 3 6 10 4 5 11
题解:
二分最大球数。
用这几个球来做最小路径覆盖
能够满足加起来等于平方数的就连边(注意 i<j).
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int N=5005,INF=1999999999; 8 int gi(){ 9 int str=0;char ch=getchar(); 10 while(ch>'9' || ch<'0')ch=getchar(); 11 while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar(); 12 return str; 13 } 14 int k,head[N],num=1,S=0,T; 15 struct Lin{ 16 int next,to,dis; 17 }a[N*10]; 18 void init(int x,int y,int dis){ 19 a[++num].next=head[x]; 20 a[num].to=y; 21 a[num].dis=dis; 22 head[x]=num; 23 a[++num].next=head[y]; 24 a[num].to=x; 25 a[num].dis=0; 26 head[y]=num; 27 } 28 bool pd(int x,int y){ 29 int tmp=sqrt(x+y); 30 if(tmp*tmp==x+y)return true; 31 return false; 32 } 33 int q[N],dep[N]; 34 bool bfs() 35 { 36 memset(dep,0,sizeof(dep)); 37 int t=0,sum=1,u,x; 38 q[1]=S;dep[S]=1; 39 while(t!=sum) 40 { 41 x=q[++t]; 42 for(int i=head[x];i;i=a[i].next){ 43 u=a[i].to; 44 if(a[i].dis<=0 || dep[u])continue; 45 dep[u]=dep[x]+1;q[++sum]=u; 46 } 47 } 48 return dep[T]; 49 } 50 int dfs(int x,int flow) 51 { 52 if(x==T || !flow)return flow; 53 int u,tmp,tot=0; 54 for(int i=head[x];i;i=a[i].next){ 55 u=a[i].to; 56 if(dep[u]!=dep[x]+1 || a[i].dis<=0)continue; 57 tmp=dfs(u,min(flow,a[i].dis)); 58 a[i].dis-=tmp;a[i^1].dis+=tmp; 59 tot+=tmp;flow-=tmp; 60 if(!flow)break; 61 } 62 return tot; 63 } 64 int maxflow() 65 { 66 int tot=0,tmp; 67 while(bfs()){ 68 tmp=dfs(S,INF); 69 while(tmp)tot+=tmp,tmp=dfs(S,INF); 70 } 71 return tot; 72 } 73 void Clear(){ 74 memset(head,0,sizeof(head)); 75 num=1; 76 } 77 bool check(int n) 78 { 79 T=(n<<1)+1; 80 for(int i=1;i<=n;i++)init(S,i,1),init(i+n,T,1); 81 for(int i=1;i<=n;i++) 82 for(int j=i+1;j<=n;j++){ 83 if(pd(i,j)) 84 init(i,j+n,INF); 85 } 86 int tp=n-maxflow(); 87 return tp<=k; 88 } 89 bool vis[N];int ans=0; 90 void putans(int x) 91 { 92 printf("%d ",x); 93 vis[x]=true; 94 for(int i=head[x];i;i=a[i].next){ 95 if(a[i].dis==INF-1)putans(a[i].to-ans); 96 } 97 } 98 int main() 99 { 100 k=gi();int l=k,r=2000,mid; 101 while(l<=r){ 102 mid=(l+r)>>1; 103 if(check(mid))ans=mid,l=mid+1; 104 else r=mid-1; 105 Clear(); 106 } 107 check(ans); 108 printf("%d\n",ans); 109 for(int i=1;i<=ans;i++){ 110 if(vis[i])continue; 111 putans(i); 112 printf("\n"); 113 } 114 return 0; 115 }