Luogu P2765

一开始看到这道题完全想不到怎么做,绞尽脑汁也想不到怎么去构造这个网络流模型。

于是查看了多篇题解……学习了多篇题解的讲解,终于找到了思路。

本文参考了洛谷

这一道题的题意并不难理解,难就难在如何去构造模型。

显然有一个贪心策略,就是尽可能地放在已经放置过球的柱子上,尽可能少地使用尚未放置球的柱子。

把每一个球视为图上的一个节点,考虑把节点\(p\)拆成两个节点,使用\(p_1\)和\(p_2\)表示,分别令超级源点\(S\)与\(p_1\)、\(p_2\)与超级汇点\(T\)连接一条容量为1的边。

若球\(i,j(i<j)\)可以匹配,则令\(i_1\)与\(j_2\)之间连接一条容量为1的边。

容量为1的原因:每次只能在柱子最上方放球。

这个时候我们求一次最大流,只要最大流有变化,即产生了新的增广路,就可以认为这个球可以放置于原先已经放置过球的柱子上了。

如果最大流没有变化,那么说明这个球必须要新开一个柱子了。

我们只需要不断地重复这个过程,直到使用的柱子恰好大于\(n\)时,此时球的编号\(-1\)就是答案。

记录方案:在跑最大流时,记录当前点给出的流到了哪个点即可;新开柱子时记录一下第一个球的编号。

举个例子



(为了方便分析已经画好了源点和汇点的所有边)

这是初始时刻的图。

当我们处理到\(3\)的时候,就可以在\(1\)和\(3'\)之间连接一条边。(为什么不在\(3,6\)连?因为\(3\)都没放哪来的\(6\))



此时产生了一条增广路,也就是说\(3\)可以放置在\(1\)所在的那个柱子上。

接着不断重复即可。

值得注意的还有这样的情况:



注意红色这一条边。因为\(1,8\)能够匹配,所以可以连上这样一条边,但是这样并不意味着\(8\)可以放置在\(1\)上,因为\(1\)上方已经有\(3,6\)了。

所以,为了处理这样的情况,我们所有的边权都是\(1\)。

不过事实上这道题直接贪心就能过了

可这是网络流24题啊

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
struct data
{
int next,to,val;
}e[50005];
int cnt=1,head[50005],cur[50005],dis[50005],rec[50005],ans[50005],n,ball;
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].val=w;
}
int bfs(int s,int t)
{
queue<int> que;
que.push(s);
for (int i=1;i<=ball*2+1;i++) dis[i]=0,cur[i]=head[i];
cur[t]=head[t];dis[t]=0;
dis[s]=1;
while (!que.empty())
{
int u=que.front();
que.pop();
for (int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if (!dis[v]&&e[i].val>0)
{
dis[v]=dis[u]+1;
if (v==t) return true;
que.push(v);
}
}
}
return false;
}
int dfs(int u,int t,int flow)
{
if (u==t||!flow) return flow;
int used=0;
for (int i=cur[u];i;i=e[i].next)
{
cur[u]=i;
int v=e[i].to;
if (dis[v]!=dis[u]+1) continue;
int tmp=dfs(v,t,min(flow-used,e[i].val));
if (!tmp) continue;
used+=tmp;
e[i].val-=tmp;
e[i^1].val+=tmp;
ans[u>>1]=v>>1;
if (flow==used) return used;
}
return used;
}
bool Dinic(int s,int t)
{
int tmp=0;
while (bfs(s,t))
tmp+=dfs(s,t,0x3f3f3f3f);
return tmp;
}
int main()
{
scanf("%d",&n);
int now=0,s=1,t=50000;
while (now<=n)
{
ball++;
add(s,ball<<1,1),add(ball<<1,s,0);
add(ball<<1|1,t,1),add(t,ball<<1|1,0);//拆点连边
for (int i=sqrt(ball)+1;i*i<(ball<<1);i++) add((i*i-ball)<<1,ball<<1|1,1),add(ball<<1|1,(i*i-ball)<<1,0);
//ball能够组成的完全平方数至少要比ball大1,但是必须小于ball的两倍
if (!Dinic(s,t)))
{
now++;
rec[now]=ball;
}
}
printf("%d\n",ball-1);
for (int i=1;i<now;i++)
{
for (int j=rec[i];j&&j!=(t>>1);j=ans[j])
printf("%d ",j);
printf("\n");
}
return 0;
}

参考资料:洛谷题解

【Luogu P2765】魔术球问题的更多相关文章

  1. luogu P2765 魔术球问题 (最小路径覆盖)

    大意:给定n根柱子, 依次放入1,2,3,...的球, 同一根柱子相邻两个球和为完全平方数, 求最多放多少个球. 对和为平方数的点连边, 就相当于求DAG上最小路径覆盖. #include <i ...

  2. luogu P2765 魔术球问题

    题目中没有说球的上限是多少,只告诉了柱子,那么我们就应该以柱子为界去增加球,考虑将每两个能组成完全平方数的点连边,就形成了一个DAG(有向无环图),由于是DAG,可以转换为最小覆盖问题,即最多有n条路 ...

  3. P2765 魔术球问题

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

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

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

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

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

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

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

  7. 【Luogu】P2765魔术球问题(没看懂的乱搞)

    题目链接 这题……讲道理我没看懂. 不过我看懂题解的代码是在干嘛了qwq 题解是zhaoyifan的题解 然后……我来讲讲这个题解好了. 题解把值为i的球拆成了两个,一个编号是i*2,一个编号是i*2 ...

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

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

  9. 洛谷P2765 魔术球问题

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

  10. 洛谷 [P2765] 魔术球问题

    贪心做法 每次尽可能选择已经放过球的柱子 #include <iostream> #include <cstdio> #include <cstring> #inc ...

随机推荐

  1. pytho模块的加载顺序

    当前目录如果有同名的系统模块,那么当前目录的模块会被import,系统模块会被忽略,如: 1 ghostwu@ghostwu:~/python/module$ ls 2 import_test.py ...

  2. C++对象内存模型1(堆栈模型)(转)

    对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立 ...

  3. 解决Mac外接显示器字体模糊的问题

    Mac外接显示器时,除非接的是Apple自家的显示器“ACD”,不然一般会遇到字体模糊发虚的问题.在终端中执行命令: defaults -currentHost write -globalDomain ...

  4. 【模板】A*B Problem(FFT快速傅里叶)

    题目:给出两个n位10进制整数x和y,你需要计算x*y.($n \leq 60000$) 分析: 两个正整数的相乘可以视为两个多项式的相乘, 例如 $15 \times 16 = 240$, 可写成 ...

  5. Task 使用方法

    Task的使用方法 1. 调用无参数.无返回值方法 private void button1_Click(object sender, EventArgs e) { Task task = new T ...

  6. Redis-基础介绍

    Redis 基础介绍 一.Redis介绍 二.Redis和Memecache的不同 三.Redis的最佳应用场景: 四.Redis支持的键值类型 五.安装Redis 六.Redis启动方式 七.Red ...

  7. MySQL 内连接、外连接、左连接、右连接、全连接……太多了

    用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). 主题:内连接 ...

  8. WinDbg常用命令系列---!dlls

    !dlls 简介 !dlls扩展显示所有加载模块或指定线程或进程正在使用的所有模块的表条目. 使用形式 !dlls [Options][LoaderEntryAddress] !dlls -h 参数 ...

  9. Js 在页面中输入消息的几种方式

    一.方式 alert(“”); confirm(“”) ; prompt(“”);         接收用户信息 console.log(“”);      在网页控制台中输出消息 document. ...

  10. 计蒜客——Reversion Count

    Reversion Count 解析:题目数字的长度最大为 99,因此使用字符串处理,那么必然这些数存在某些规律.对于数 a (XYZW) 和数 b (WZYX),原式 = (1000X + 100Y ...