魔术球问题[网络流24题之4]
2016-05-19 18:01
288 查看
问题描述:
假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,... 的球。(1) 每次只能在某根柱子的最上面放球。
(2) 在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多可放 11 个球。
编程任务:
对于给定的 n ,计算在 n 根柱子上最多能放多少个球。数据输入:
第 1 行有 1 个正整数 n ,表示柱子数。结果输出:
n 根柱子上最多能放的球数输入示例:
4输出示例:
11分析:
这个题目和最小路径覆盖问题差不多(几乎是一样的),对于每一个 x+y=i2(x<y),依照题意我们知道 x,y 都能且只能使用一次,所以我们可以把每一个数字 x 拆成 x1 和 x0,其中 x1 加上一个比 x1 小的数字构成一个完全平方数, x0 加上一个比 x0 大的数构成一个完全平方数,再把所有的 (y0,z1)(y0+z1=i2,y0<z1,i∈N+) 之间连一条有向边就是一个二分图匹配的问题了,下面给出构造图 N 的过程1 :新增一个源 S 和汇 T
2 :把当前的整数 x 拆成 x0 和 x1
3 :连接一条容量为 1 ,从 S 到 x0 的有向边
4 :连接一条容量为 1 ,从 x1 到 T 的有向边
5 :连接一条容量为 1 ,从 x0 到 k(x0+k=i2,k∈N+,i∈N+) 的有向边
对于每一个数字执行完以上的 2−5 步之后如果不能在图 N 增加一点流量的话,就需要用一个新的柱子,当需要第 n+1 根柱子是,程序结束,当前数字减一就是最后的解
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; int tot; int head[4747],nxt[47047],to[47047],wei[47047]; int c[4747]; int que[4747]; int n; int num; int now; void add(int,int); bool bfs(); bool dinic(int); int main(){ freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); scanf("%d",&n); while(now <= n){ ++num; add(1,num<<1); add((num<<1)+1,146); for(int i=sqrt(num)+1;i*i<(num<<1);i++) add((i*i-num)<<1,(num<<1)+1); if(bfs()) dinic(1); else ++now; } printf("%d",num-1); return 0; } void add(int from,int tp){ ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=1; ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0; } bool bfs(){ memset(c,0,sizeof c); c[1] = 1; que[1] = 1; int H=0,T=1,now; do{ now = que[++H]; for(int i=head[now];i;i=nxt[i]) if(!c[to[i]] && wei[i]){ c[to[i]] = c[now]+1; que[++T] = to[i]; } }while(H<T); return c[146]; } bool dinic(int place){ if(place == 146) return true; for(int i=head[place];i;i=nxt[i]) if(c[to[i]]==c[place]+1 && wei[i]) if(dinic(to[i])){ --wei[i]; ++wei[i^1]; return true; } return false; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性