【Luogu P2765】魔术球问题
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】魔术球问题的更多相关文章
- luogu P2765 魔术球问题 (最小路径覆盖)
大意:给定n根柱子, 依次放入1,2,3,...的球, 同一根柱子相邻两个球和为完全平方数, 求最多放多少个球. 对和为平方数的点连边, 就相当于求DAG上最小路径覆盖. #include <i ...
- luogu P2765 魔术球问题
题目中没有说球的上限是多少,只告诉了柱子,那么我们就应该以柱子为界去增加球,考虑将每两个能组成完全平方数的点连边,就形成了一个DAG(有向无环图),由于是DAG,可以转换为最小覆盖问题,即最多有n条路 ...
- P2765 魔术球问题
P2765 魔术球问题 贪心模拟就可以过.........好像和dinic没啥关系 找找规律发现可以贪心放.n又灰常小. 设答案=m 你可以$O(mn)$直接模拟过去 闲的慌得话可以像我用个$se ...
- 洛谷 P2765 魔术球问题 解题报告
P2765 魔术球问题 题目描述 问题描述: 假设有\(n\)根柱子,现要按下述规则在这\(n\)根柱子中依次放入编号为\(1,2,3,\dots\)的球. \((1)\) 每次只能在某根柱子的最上面 ...
- 洛谷 P2765 魔术球问题 (dinic求最大流,最小边覆盖)
P2765 魔术球问题 题目描述 «问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2 ...
- P2765 魔术球问题 网络流二十四题重温
P2765 魔术球问题 知识点::最小点覆盖 这个题目要拆点,这个不是因为每一个球只能用一次,而是因为我们要求最小点覆盖,所以要拆点来写. 思路: 首先拆点,然后就是开始建边,因为建边的条件是要求他们 ...
- 【Luogu】P2765魔术球问题(没看懂的乱搞)
题目链接 这题……讲道理我没看懂. 不过我看懂题解的代码是在干嘛了qwq 题解是zhaoyifan的题解 然后……我来讲讲这个题解好了. 题解把值为i的球拆成了两个,一个编号是i*2,一个编号是i*2 ...
- 洛谷P2765魔术球问题 最小路径覆盖
https://www.luogu.org/problemnew/show/P2765 看到这一题第一眼想到:这不是二分最大流吗,后来发现还有一种更快的方法. 首先如果知道要放多少个球求最少的柱子,很 ...
- 洛谷P2765 魔术球问题
题目链接:https://www.luogu.org/problemnew/show/P2765 知识点: 最大流 解题思路: 本题所有边的容量均为 \(1\). 从 \(1\) 开始加入数字,将这个 ...
- 洛谷 [P2765] 魔术球问题
贪心做法 每次尽可能选择已经放过球的柱子 #include <iostream> #include <cstdio> #include <cstring> #inc ...
随机推荐
- 深度学习Keras框架笔记之AutoEncoder类
深度学习Keras框架笔记之AutoEncoder类使用笔记 keras.layers.core.AutoEncoder(encoder, decoder,output_reconstruction= ...
- 网站安全DDOS攻击及监测
一. 监测 在类Unix系统中可以使用top查看系统资源.进程.内存占用等信息.查看网络状态可以使用netstat.nmap等工具.若要查看实时的网络流量,监控TCP/IP连接等,则可以使用iftop ...
- include指令 include动作
- Java 用Jackson进行json和object之间的转换(并解决json中存在新增多余字段的问题)
1.添加jackson库 如果是maven工程,需要在pom.xml中添加jackson的依赖: <dependency> <groupId>com.fasterxm ...
- H5利用formData来上传文件(包括图片,doc,pdf等各种格式)方法小结!
H5页面中我们常需要进行文件上传,那么怎么来实现这个功能呢??? 我主要谈如下两种方法. (一).传统的form表单方法 <form action="/Home/SaveFile1&q ...
- PowerDesigner 创建表的时候 没有自增长Id的设置项
今天早上同事创建表的时候,在那个界面没有自增长Id的选项,当时我也纳闷,软件肯定都是一样的,设置的步骤都一样(有些配置好的 我就没改过 然后就忘了还改过些什么步骤了),结果还是没有那个选项 百度了一下 ...
- 用pandas进行数据清洗(二)(Data Analysis Pandas Data Munging/Wrangling)
在<用pandas进行数据清洗(一)(Data Analysis Pandas Data Munging/Wrangling)>中,我们介绍了数据清洗经常用到的一些pandas命令. 接下 ...
- 表单提交 curl和浏览器方式
表单被提交时,每个表单域都会被Url编码之后才在被发送. 浏览器每次向服务器发送url时,会进行编码,然后web服务器再进行解码. 所以,理论上,curl模拟登陆时,所传参数都必须urlencode一 ...
- uni-app 模拟器
1.安装MuMu模拟器 Android模拟器端口: 7555 2.安装夜神模拟器 Android模拟器端口: 62001
- 更改matlab默认精度
我使用的是R2018a 1.打开预设 2.命令行窗口 3.变量