• 魔术球问题(网络流24题)


    问题描述:

    假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。

    (1)每次只能在某根柱子的最上面放球。

    (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

    试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

    «编程任务:

    对于给定的n,计算在n根柱子上最多能放多少个球。

    4<=n<=55

    题解

    考虑到当球的数量增加时柱子数量不严格单增,所以可以一个一个加球判定需要几个柱子装得下。

    把每个球拆成两个点,互成平方数的两个球左右连边,为了确保只连一次从大的向小的连边。

    那么问题就变成了最小路径覆盖,路径数就是柱子数。

    枚举球为m个,当路径数大于柱子数时答案就是m-1,至于输出方案就从1遍历路径就好了。

    为了不超时,我们新加一个球,就从这个球跑一次增广路即可,这也是为什么从大的往小的连边。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=3605;
    int n,m;
    int vis[maxn],match[maxn],timer;
    bool square[maxn<<1];
    vector<int> e[maxn];
    
    void init(){
      timer=0;
      memset(match,0,sizeof(match));
      memset(vis,0,sizeof(vis));
    }
    
    bool dfs(int u){
      if(vis[u]==timer) return false;
      vis[u]=timer;
      for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(!match[v]||dfs(match[v])){
          match[v]=u;
          return true;
        }
      }
      return false;
    }
    
    void get(int u){
      printf("%d ",u);
      vis[u]=timer;
      if(!match[u+1800]){putchar(10);return ;}
      get(match[u+1800]);
    }
    
    void print(){
      ++timer;
      for(int i=1;i<m;i++)
        if(vis[i]!=timer) get(i);
    }
    
    int main(){
      for(int i=1;i*i<=7200;i++)
       square[i*i]=true;
      scanf("%d",&n);
      int ans=0;
      while(++m){
        for(int i=1;i<m;i++)
         if(square[i+m]) e[m].push_back(i+1800);
        ++timer;
        if(dfs(m)) ans++;
        if(m-ans>n) {printf("%d
    ",m-1);print();exit(0);}
      }
    }
    View Code

     还有贪心的方法,有可以放的柱子就放,不然就新开(正确性就不知道了)。

    貌似球的数量还有规律2+2+4+4+6+6+....

  • 相关阅读:
    GIS开发站点收藏
    读取Excel中的数据到DataSet
    SPSS统计功能与模块对照表
    相关性分析主要源码
    Matlab典型论坛
    EasyUI入门视频教程
    利用EF ORM Mysql实体运行程序出错解决方案
    小议
    六、 从Controller中访问模板数据(ASP.NET MVC5 系列)
    五、 创建连接串连接本地数据库(ASP.NET MVC5 系列)
  • 原文地址:https://www.cnblogs.com/sto324/p/11334014.html
Copyright © 2020-2023  润新知