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. git提交项目到已有库

    借鉴地址:https://blog.csdn.net/jerryhanjj/article/details/72777618 Git global setup git config --global ...

  2. 学习Microsoft Visio(2)

    常用业务设计图示法 一.业务设计基础 1.名词概念 业务流程图:在公司.部门.岗位的层面上描述一个业务流程的宏观过程. 基本流程图:对某个处理过程的详细逻辑流程进行描述. 静态业务对象图(UML表示法 ...

  3. zabbix4.2.5默认告警模板

    产生告警: Problem: {EVENT.NAME} Problem started at {EVENT.TIME} on {EVENT.DATE} Problem name: {EVENT.NAM ...

  4. python面试题&练习题之嵌套循环

    1.打印如下结果: 1*5=5 2*10=20 3*15=45 ... 10*50=500 for i in range(1,11): print(str(i)+'x'+str((i*5))+'='+ ...

  5. 题解 UVa11609

    题目大意 给定一个正整数 \(n\),请求出所有小于 \(n\) 人的团队如果选出一个人作为队长的不同的方案数(假定这些人两两不相同)对 \(10^9+7\)取模的结果. 分析 即求 \[\sum^n ...

  6. Python 3的 bytes 数据类型

    """b'\xe6\x88\x91\xe7\x88\xb1Python\xe7\xbc\x96\xe7\xa8\x8b'代表这是一个字节窜,\x代表十六进制表示 e6是十 ...

  7. MySQL入门篇之mysqldump备份和恢复

    一.备份单个数据库 1.备份命令:mysqldump MySQL数据库自带的一个很好用的备份命令.是逻辑备份,导出 的是SQL语句.也就是把数据从MySQL库中以逻辑的SQL语句的形式直接输出或生成备 ...

  8. windows下dos窗口实现持续ping显示时间保存至日志

    效果图 右击新建 ping.bat 文件(ping为文件名称,随便起),内容如下: cscript ping.vbs  127.0.0.1 -t >log.txt 127.0.0.1 修改为你自 ...

  9. LeetCode 731. My Calendar II

    原题链接在这里:https://leetcode.com/problems/my-calendar-ii/ 题目: Implement a MyCalendarTwo class to store y ...

  10. 防火墙firewalld

    增加外部可访问的端口 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl stop firewal ...