线性规划与网络流24题——04魔术球问题
来源:互联网 发布:起点数据查询 编辑:程序博客网 时间:2024/04/29 04:23
1739:魔术球问题
Time Limit:1000MS Memory Limit:65536K
Total Submit:39 Accepted:20 Page View:230 Special Judged
[Submit] [Status] [Discuss]
Font Size: Aa Aa Aa
Description
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。(1)每次只能在某根柱子的最上面放球。(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。编程任务:对于给定的n,计算在n根柱子上最多能放多少个球。
Input
由文件input.txt提供输入数据。文件第1 行有1个正整数n(n<=55),表示柱子数。
Output
程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出到文件output.txt中。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。
Sample Input
4
Sample Output
111 82 7 93 6 104 5 11
【问题分析】
枚举答案转化为判定性问题,然后最小路径覆盖,可以转化成二分图最大匹配,从而用最大流解决。
【建模方法】
枚举答案A,在图中建立节点1..A。如果对于i<j有i+j为一个完全平方数,连接一条有向边(i,j)。该图是有向无环图,求最小路径覆盖。如果刚好满足最小路径覆盖数等于N,那么A是一个可行解,在所有可行解中找到最大的A,即为最优解。
具体方法可以顺序枚举A的值,当最小路径覆盖数刚好大于N时终止,A-1就是最优解。
【建模分析】
由于是顺序放球,每根柱子上的球满足这样的特征,即下面的球编号小于上面球的编号。抽象成图论,把每个球看作一个顶点,就是编号较小的顶点向编号较大的顶点连接边,条件是两个球可以相邻,即编号之和为完全平方数。每根柱子看做一条路径,N根柱子要覆盖掉所有点,一个解就是一个路径覆盖。
最小路径覆盖数随球的数量递增不递减,满足单调性,所以可以枚举答案(或二分答案),对于特定的答案求出最小路径覆盖数,一个可行解就是最小路径覆盖数等于N的答案,求出最大的可行解就是最优解。本问题更适合枚举答案而不是二分答案,因为如果顺序枚举答案,每次只需要在残量网络上增加新的节点和边,再增广一次即可。如果二分答案,就需要每次重新建图,大大增加了时间复杂度。
代码:
#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#define maxn 100000#define eps 0.000000001#define INF 1 << 30using namespace std;struct E{ int from, to, next, tab;}edge[200000];int tot, s, t, n, ans, K;int head[maxn], d[maxn], dist[maxn], vis[maxn]; void add_edge(int u, int v, int f){ edge[tot].from = u, edge[tot].to = v, edge[tot].tab = f, edge[tot].next = head[u], head[u] = tot++; edge[tot].from = v, edge[tot].to = u, edge[tot].tab = 0, edge[tot].next = head[v], head[v] = tot++;} int dfs(int x, int low){ int a, b = 0; if (x == t) return low; for (int i = head[x]; i != -1 && low; i = edge[i].next) if (edge[i].tab > 0 && dist[edge[i].to] == dist[x] + 1 && (a = dfs(edge[i].to, min(low, edge[i].tab)))) { edge[i].tab -= a, edge[i ^ 1].tab += a; low -= a; b += a; } return b;} int bfs(){ int l, r, k; memset(dist, 0xff, sizeof(dist)); l = r = dist[s] = 0; d[r++] = s; while (l < r) { k = d[l++]; for (int i = head[k]; i != -1; i =edge[i].next) if (edge[i].tab > 0 && dist[edge[i].to] < 0) { dist[edge[i].to] = dist[k] + 1; if (edge[i].to == t) return 1; d[r++] = edge[i].to; } } return 0;} void dinic(){ while (bfs()) ans += dfs(s, INF);} int check(int m, int n){ int sum = m+n; double dsum = sqrt(sum); int tem = (int)dsum; if (dsum-tem < eps) return 1; else return 0;} void print(int u, int clr){ vis[u] = clr; int v, flag = 1; for (int i = head[u*2]; i != -1; i = edge[i].next) { v = edge[i].to; if (edge[i].tab == 0 && v!= s) { flag = 0; break; } } if (!flag) print(v/2, clr);} int main(){ memset(head, 0xff, sizeof(head)); scanf("%d", &K); n = ans = s = 0, t = 1; tot = 0; while (n-ans <= K) { n++; add_edge(s, n*2, 1); add_edge(n*2+1, t, 1); for (int i = 1; i < n; i++) if (check(i, n)) add_edge(i * 2, n * 2 + 1, 1); dinic(); } n--; printf("%d\n", n); memset(vis, 0xff, sizeof(vis)); int clr = 0; for (int j = 1; j <= n; j++) if (vis[j] == -1) print(j, clr++); for (int k = 0; k < clr; k++) { int first = 1; for (int j = 1; j<= n; j++) if (vis[j] == k) { if (first) printf("%d", j), first = 0; else printf(" %d", j); } printf("\n"); } return 0;}
- 线性规划与网络流24题 04魔术球问题
- 网络流与线性规划24题04魔术球问题
- 线性规划与网络流24——魔术球问题
- 线性规划与网络流24题——04魔术球问题
- 线性规划与网络流24题之 魔术球问题
- 【线性规划与网络流24题 4】魔术球
- 线性规划与网络流24题の4 魔术球问题(最小路径覆盖)
- 线性规划与网络流24——太空飞行计划问题
- 线性规划与网络流24——圆桌问题
- 线性规划与网络流24——试题库问题
- 线性规划与网络流24——餐巾计划问题
- 线性规划与网络流24——分配问题
- 线性规划与网络流24——骑士共存问题
- 线性规划与网络流24——负载平衡问题
- 线性规划与网络流24——运输问题
- 线性规划与网络流24——星际转移问题
- 线性规划与网络流24——数字梯形问题
- 线性规划与网络流24——航空路线问题
- java基础部分-《第二部分》-异常机…
- 数据库优化
- java工作、面试等细说
- mysql:超过8小时后连接池异常和解决方法
- c3p0_百度百科
- 线性规划与网络流24题——04魔术球问题
- JS限制上传文件类型和大小(不是宽…
- PHP分页技术通用模版
- 通讯录管理系统
- 绿色网络投票平台
- 何为B2B、B2C、C2C、C2B?
- 何为SNS?
- [转]MYSQL初学者使用指南
- PHP-开发【IBOS】中【常用有用的代…