【网络流24题】魔术球问题 二分答案+最小路径覆盖

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。 (1)每次只能在某根柱子的最上面放球。 (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。 试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可 放11 个球。 编程任务: 对于给定的n,计算在n根柱子上最多能放多少个球。
由文件input.txt提供输入数据。文件第1 行有1个正整数n(n<=55),表示柱子数。
程序运行结束时,将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 }

 

posted @ 2017-05-21 20:25  PIPIBoss  阅读(210)  评论(0编辑  收藏  举报