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

Posted sto324

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔术球问题(网络流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\n",m-1);print();exit(0);
  
View Code

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

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

以上是关于魔术球问题(网络流24题)的主要内容,如果未能解决你的问题,请参考以下文章

网络流24题魔术球问题

[loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

「Luogu2765」[网络流24题] 魔术球问题

网络流24题魔术球

网络流24题魔术球问题(最小不相交路径覆盖)

网络流24题 #04魔术球问题