[网络流24题]魔术球问题(简化版

来源:互联网 发布:终极算法 pdf 编辑:程序博客网 时间:2024/06/01 16:27

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

´数据输入: 文件第1 行有 1个正整数n,表示柱子数。 ´结果输出: 文件的第一行是球数。

数据规模

n<=60  保证答案小于1600

输入文件示例

4

输出文件示例

11

方案如下

1 8 2 7 9 3 6 10 4 5 11

每一行表示一个柱子上的球

在上一次的残余网络建新边-》(由于从[1~...]按顺序+反向边)-》得新的流
就是编号较小的顶点向编号较大的顶点连接边(皆可),条件是两个球可以相邻,即编号之和为完全平方数。每根柱子看做一条路径,N根柱子要覆盖掉所有点,一个解就是一个路径覆盖。
最小路径覆盖数随球的数量递增不递减,满足单调性,所以可以枚举答案(或二分答案),对于特定的答案求出最小路径覆盖数,一个可行解就是最小路径覆盖数等于N的答案,求出最大的可行解就是最优解。本问题更适合枚举答案而不是二分答案,因为如果顺序枚举答案,每次只需要在残量网络上增加新的节点和边,再增广一次即可。如果二分答案,就需要每次重新建图,大大增加了时间复杂度。
#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<queue>#include<map>#include<cstdlib>#include<algorithm>#define V 10605#define mod 1000000007#define LL long longusing namespace std;int n,m,T,S;int ls[V],pre[V],dep[V],q[V];struct da{ int to,next,dis;       }Edge[V*15];int head[V],tot,ans,s;inline void add(int x,int y,int zz){  Edge[tot].to=y;  Edge[tot].dis=zz;  Edge[tot].next=head[x];  head[x]=tot++;    Edge[tot].to=x;  Edge[tot].dis=0;  Edge[tot].next=head[y];  head[y]=tot++;     }bool Bfs() { // bfs建立层次图     memset(dep, 0, sizeof(dep));    int hd,tl;    hd = tl = 0;    q[++ tl] = S, dep[S] = 1;    while(hd<tl) {        int op = q[++hd];        for(int i = head[op] ; i != -1 ; i = Edge[i].next) {            if(Edge[i].dis&&(!dep[Edge[i].to])) {                dep[Edge[i].to] = dep[op]+1;                q[++ tl] = Edge[i].to;                if(Edge[i].to==T) return true;            } // 遍历到T就返回,此时该层次图已建好         } // 再访问其它的点没有必要     }    return false;}int Dfs(int op, int fw) {    if(op==T) return fw;               int tmp =fw,k;    for(int i = head[op] ; i != -1 ; i = Edge[i].next) {        if(Edge[i].dis&&tmp&&dep[Edge[i].to]==dep[op]+1) {            k = Dfs(Edge[i].to, min(Edge[i].dis, tmp));            if(!k) { //该点后面没有路径,所以要从层次图中删去                dep[Edge[i].to] = 0; // 因为和当前点op层次相同的点                 continue; // 还可能会访问到它             }            Edge[i].dis-= k, Edge[i^1].dis+= k,tmp-= k;        }    }    return fw-tmp;}int solve(){   int i,flow=0;   while(Bfs())   {    ans-=Dfs(S,mod);               }   return flow;}inline void init(){       tot=0;   memset(head,-1,sizeof(head));       } int vis[V];inline int haha(){   // freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);    freopen("balla.in","r",stdin); freopen("balla.out","w",stdout);    memset(head,-1,sizeof(head));    cin>>n;    T=2*1600+10;    while(ans<=n)    {      ans++;s++;      for(int i=1;i<s;i++)      if(sqrt(i+s)==(int)sqrt(i+s))                        add(s,i+1600,1);       add(0,s,1);add(s+1600,T,1);       solve();     }    //return 0;    printf("%d",s-1);//while(1);    return 0;    /*int sd=s-1,x;    while(1)    {        for(int i=s-1;i>=1;i--)        {          cout<<i<<endl;          if(!vis[i])          {                     vis[i]=1;              for(int j=head[i];j!=-1;j=Edge[j].next)              {                if(!Edge[j].dis)                {                  //x=1;                    sd--;                   ls[Edge[j].to]=i;                                      i=Edge[j].to+1;                   break;                             }                      }          }        }        if(sd==1)break;        //cout<<" ER"<<endl;    }    */    return 0;}int gg=haha();int main(){;}