贪心做法

每次尽可能选择已经放过球的柱子

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <cmath>
  6. using namespace std;
  7. int num[100][1000],n;
  8. bool chk(const int &a,const int &b){
  9. int t=sqrt(a+b);
  10. return t*t==a+b;
  11. }
  12. int main(){
  13. cin>>n;
  14. int cnt=0;
  15. while(++cnt){
  16. bool f=0;
  17. for(int i=1;i<=n;i++){
  18. if(num[i][0]&&chk(num[i][num[i][0]],cnt)) num[i][++num[i][0]]=cnt,f=1;
  19. if(f) break;
  20. }
  21. for(int i=1;i<=n;i++){
  22. if(!num[i][0]) num[i][++num[i][0]]=cnt,f=1;
  23. if(f) break;
  24. }
  25. if(!f) break;
  26. }
  27. printf("%d\n",cnt-1);
  28. for(int i=1;i<=n;i++){
  29. for(int j=1;j<=num[i][0];j++){
  30. printf("%d ",num[i][j]);
  31. }
  32. printf("\n");
  33. }
  34. return 0;
  35. }

网络流做法

我们可以将其转化成最小路径覆盖问题来做,

从小到大枚举答案,对于每一个新加进去的答案,寻找在已加进去的点中,满足题意的点,连一条边.

我们发现连好以后这是一个DAG图,其最小路径覆盖就是需要的最少柱子数,我们要找到一个最小路径覆盖<=n的最大解,即最后的答案

求最小路径覆盖可以用二分图做

这里有几个优化,具体见代码

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <algorithm>
  6. #include <queue>
  7. #include <cmath>
  8. using namespace std;
  9. int init(){
  10. int rv=0,fh=1;
  11. char c=getchar();
  12. while(c<'0'||c>'9'){
  13. if(c=='-') fh=-1;
  14. c=getchar();
  15. }
  16. while(c>='0'&&c<='9'){
  17. rv=(rv<<1)+(rv<<3)+c-'0';
  18. c=getchar();
  19. }
  20. return fh*rv;
  21. }
  22. const int MAXN=5000,MAXM=50005;
  23. int head[MAXN],n,cur[MAXN],dep[MAXN],nume,s,t,maxflow;
  24. queue<int> q;
  25. bool f[MAXN];
  26. struct edge{
  27. int to,nxt,cap,flow;
  28. }e[MAXM<<1];
  29. void adde(int from,int to,int cap){
  30. e[++nume].to=to;
  31. e[nume].nxt=head[from];
  32. head[from]=nume;
  33. e[nume].cap=cap;
  34. }
  35. bool chk(const int &a,const int &b){
  36. int t=sqrt(a+b);
  37. return t*t==a+b;
  38. }
  39. bool bfs(){
  40. memset(dep,0,sizeof(dep));
  41. while(!q.empty()) q.pop();
  42. q.push(s);dep[s]=1;
  43. while(!q.empty()){
  44. int u=q.front();q.pop();
  45. for(int i=head[u];i;i=e[i].nxt){
  46. int v=e[i].to;
  47. if(!dep[v]&&e[i].flow<e[i].cap){
  48. dep[v]=dep[u]+1;
  49. if(v==t) return 1;//搜到汇点就结束,因为最新加进来的点一定在最前面,所以,搜到的这条路径就是新加进来的路径
  50. q.push(v);
  51. }
  52. }
  53. }
  54. return 0;
  55. }
  56. int dfs(int u,int flow){
  57. if(u==t) return flow;
  58. int tot=0;
  59. for(int &i=cur[u];i&&tot<flow;i=e[i].nxt){
  60. int v=e[i].to;
  61. if(dep[v]==dep[u]+1&&e[i].flow<e[i].cap){
  62. if(int t=dfs(v,min(flow-tot,e[i].cap-e[i].flow))){
  63. e[i].flow+=t;
  64. e[((i-1)^1)+1].flow-=t;
  65. tot+=t;
  66. }
  67. }
  68. }
  69. return tot;
  70. }
  71. void dinic(){
  72. while(bfs()){
  73. for(int i=s;i<=t;i++) cur[i]=head[i];
  74. maxflow+=dfs(s,0x3f3f3f3f);
  75. }
  76. }
  77. void print(int u){
  78. printf("%d ",u);
  79. f[u]=1;
  80. for(int i=head[u];i;i=e[i].nxt){
  81. int v=e[i].to-2000;
  82. if(!f[v]&&e[i].flow){
  83. print(v);
  84. return;
  85. }
  86. }
  87. }
  88. int main(){
  89. n=init();
  90. s=0,t=4950;
  91. int cnt=0;
  92. while(++cnt){
  93. adde(s,cnt,1);adde(cnt,s,0);
  94. adde(cnt+2000,t,1);adde(t,cnt+2000,0);
  95. for(int i=1;i<cnt;i++){
  96. if(chk(i,cnt)){
  97. adde(i,cnt+2000,1);
  98. adde(cnt+2000,i,0);
  99. }
  100. }
  101. dinic();
  102. if(cnt-maxflow>n) break;
  103. }
  104. printf("%d\n",cnt-1);
  105. for(int k=1;k<=n;k++){
  106. for(int i=1;i<cnt;i++) if(!f[i]){
  107. print(i);break;
  108. }
  109. printf("\n");
  110. }
  111. return 0;
  112. }

洛谷 [P2765] 魔术球问题的更多相关文章

  1. 洛谷 P2765 魔术球问题 解题报告

    P2765 魔术球问题 题目描述 问题描述: 假设有\(n\)根柱子,现要按下述规则在这\(n\)根柱子中依次放入编号为\(1,2,3,\dots\)的球. \((1)\) 每次只能在某根柱子的最上面 ...

  2. 洛谷 P2765 魔术球问题 (dinic求最大流,最小边覆盖)

    P2765 魔术球问题 题目描述 «问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2 ...

  3. 洛谷P2765魔术球问题 最小路径覆盖

    https://www.luogu.org/problemnew/show/P2765 看到这一题第一眼想到:这不是二分最大流吗,后来发现还有一种更快的方法. 首先如果知道要放多少个球求最少的柱子,很 ...

  4. 洛谷P2765 魔术球问题(最大流)

    传送门 %%%KSkun大佬 话说明明是网络流……这题竟然还有打表找规律和纯贪心AC的……都是神犇啊…… 来说一下如何建图.首先把每一个点拆成$X_i$和$Y_i$,然后$S$向$X_i$连一条容量为 ...

  5. 洛谷P2765 魔术球问题(贪心 最大流)

    题意 已经很简洁了吧. 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全 ...

  6. 洛谷P2765 魔术球问题

    题目链接:https://www.luogu.org/problemnew/show/P2765 知识点: 最大流 解题思路: 本题所有边的容量均为 \(1\). 从 \(1\) 开始加入数字,将这个 ...

  7. P2765 魔术球问题

    P2765 魔术球问题 贪心模拟就可以过.........好像和dinic没啥关系   找找规律发现可以贪心放.n又灰常小. 设答案=m 你可以$O(mn)$直接模拟过去 闲的慌得话可以像我用个$se ...

  8. P2765 魔术球问题 网络流二十四题重温

    P2765 魔术球问题 知识点::最小点覆盖 这个题目要拆点,这个不是因为每一个球只能用一次,而是因为我们要求最小点覆盖,所以要拆点来写. 思路: 首先拆点,然后就是开始建边,因为建边的条件是要求他们 ...

  9. [洛谷P2113] 看球泡妹子

    洛谷题目链接:看球泡妹子 题目背景 2014年巴西世界杯开幕了,现在满城皆是世界杯,商家们利用它大赚一笔,小明和小红也借此机会增进感情. 题目描述 本届世界杯共有N支球队,M场比赛.男球迷小明喜欢看比 ...

随机推荐

  1. python数据类型(二)

    一.List(列表) List(列表) 是 Python 中使用最频繁的数据类型. 列表可以完成大多数集合类的数据结构实现.列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套). ...

  2. 怎样实现给DEDE的栏目增加栏目图片(1)

    http://www.genban.org/news/dedecms-7577.html 前两天用DEDE做二次开发的时候,遇到一个问题,领导让给每个栏目增加一个栏目图片的功能,网上找了些东西,结合自 ...

  3. ThinkPhp_5框架开发【指导】

    ================================================== ThinkPhp_5环境安装指导 -------------------------------- ...

  4. 最简Java程序

    本文是笔者创建项目--一系列java示例程序的总结.项目位置在SimplestJavaDemos,欢迎访问. 以下为正文: ---   作为一个伪完美主义+拖延癌患者,每次要学习新技术的时候,总是要把 ...

  5. @synchronized(self)

    @synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改.这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其 它线程访问,起到线程的保护 ...

  6. JAVA BASE64

    Base64编码说明:     Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式. 如果剩下的字符不足3个字节, ...

  7. 为什么我不愿意用ECharts

    前言 ECharts是百度一个使用 JavaScript 实现的开源可视化库,提供了创建多种多样的图标方式,包括坐标系,图例,提示,工具箱等基础组件,并在此上构建出折线图.柱状图.散点图.K线图.饼图 ...

  8. Django实现组合搜索

    一.实现方法 1.纯模板语言实现 2.自定义simpletag实现(本质是简化了纯模板语言的判断) 二.基本原理 原理都是通过django路由系统,匹配url筛选条件,将筛选条件作为数据库查询结果,返 ...

  9. Shell中脚本变量的作用域

    原文地址:http://blog.csdn.net/abc86319253/article/details/46341839    在shell中定义函数可以使代码模块化,便于复用代码.不过脚本本身的 ...

  10. trait

    参考 引文 在php中,为实现代码复用,有了继承,但是一个类只能继承一个父类,不支持多继承,接口支持多实现,但是接口又不太一样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑 ...