网络流24题4. 魔术球问题
2017-03-02 16:16
246 查看
魔术球问题
Description
假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,…的球。(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多可放 11 个球。
对于给定的 n,计算在 n 根柱子上最多能放多少个球。
Input
文件第 1 行有 1 个正整数 n,表示柱子数。Output
将 n 根柱子上最多能放的球数以及相应的放置方案输出。第一行是球数。接下来的 n 行,每行是一根柱子上的球的编号。题解
直接求解较为困难,考虑转化为判定性问题,即在n根柱子上能不能放a个球。a个球在柱子上从下到上必然是从小到大的,那么两个球如果能放在一起(和伟完全平方数)那么就将他们之间连一条从小编号指向大编号的有向边,如此一来,每根柱子可以看做是这个途中的一条路径,而用最小路径覆盖就可以求出最少需要的柱子数量。那么我们从小到大枚举a,一旦最小路径覆盖数大于n,那么a-1就是答案。方案也只需找到有向图对应的二分图中的匹配即可。
在实际实现的过程中,从小到大枚举a,每次只需要在上次计算过的残量网络中添加一些边再继续增广即可,比二分答案然后每次重新建图的时间复杂度小许多。
#include<cstdio> #include<cmath> #include<iostream> #include<cstring> using namespace std; const int N = 5000 + 10, M = 500000 + 10, inf = 0x3f3f3f3f; struct Edge{ int fr, to, cap, flow; }edg[M]; int hd , nxt[M]; int d , vis , q , dfn; int s, t; int n, ans, tot; bool is_sq ; void insert(int u, int v, int w){ edg[tot].fr = u, edg[tot].to = v, edg[tot].cap = w; nxt[tot] = hd[u], hd[u] = tot; tot++; edg[tot].fr = v, edg[tot].to = u; nxt[tot] = hd[v], hd[v] = tot; tot++; } bool bfs(){ int head = 1, tail = 1; q[1] = s; vis[s] = ++dfn; d[s] = 0; while(head <= tail){ int u = q[head++]; for(int i = hd[u]; i >= 0; i = nxt[i]){ Edge &e = edg[i]; if(vis[e.to] == dfn || e.cap <= e.flow) continue; vis[e.to] = dfn; d[e.to] = d[u] + 1; q[++tail] = e.to; } } return vis[t] == dfn; } int dfs(int x, int a){ if(x == t || a == 0) return a; int flow = 0, f; for(int i = hd[x]; i >= 0; i = nxt[i]){ Edge &e = edg[i]; if(d[e.to] == d[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0){ flow += f; e.flow += f; edg[i^1].flow -= f; a -= f; if(a == 0) break; } } return flow; } void work(){ scanf("%d", &n); memset(hd, -1, sizeof(hd)); s = 0; t = 1; for(int i = 1; i * i <= 5000; i++) is_sq[i*i] = 1; for(int a = 1, tmp = 1; ; a++, tmp++){ insert(s, a<<1, 1); insert(a<<1|1, t, 1); for(int i = 1; i < a; i++) if(is_sq[a+i]) insert(i<<1, a<<1|1, 1); while(bfs()) tmp -= dfs(s, inf); if(tmp > n){ printf("%d\n", a - 1); break; } } } int main(){ freopen("prog84.in", "r", stdin); freopen("prog84.out", "w", stdout); work(); return 0; }
相关文章推荐
- [网络流24题]魔术球问题 贪心||枚举答案+最小路径覆盖
- 【网络流24题】No.4 魔术球问题 (二分+最小路径覆盖)
- 【网络流24题】魔术球问题 二分答案+最小路径覆盖
- [网络流24题] 魔术球问题
- [网络流24题]魔术球问题
- cogs 396. [网络流24题]魔术球问题(简化版
- 线性规划与网络流24——魔术球问题
- 【网络流24题】魔术球问题
- [网络流24题]魔术球问题(简化版) 最小路径覆盖+二分答案 + 很快的最大流
- 洛谷2765:[网络流24题]魔术球问题——题解
- 396. [网络流24题]魔术球问题(简化版
- COGS396. [网络流24题]魔术球问题(简化版
- 网络流24题 魔术球问题(弱化?)(二分图解)
- [网络流24题-2]cogs396魔术球问题
- 【网络流24题】魔术球问题
- 魔术球问题[网络流24题之4]
- cogs396 [网络流24题]魔术球问题简化版
- [网络流24题]魔术球问题(简化版
- 【网络流24题】魔术球问题(最大流)
- [网络流24题]魔术球问题