题目描述:这里

这道题是网络流问题中第一个难点,也是一个很重要的问题

如果直接建图感觉无从下手,因为如果不知道放几个球我就无法得知该如何建图(这是很显然的,比如我知道 $1+48=49=7^2$ ,可是我都不知道是否能放到第48个球,那我怎么知道如何建边呢?)

所以这时就体现出了一个很重要的想法:枚举答案!!!

我们知道,正常有二分答案的做法,可以二分一个答案然后检验

这里用类似的想法,但由于答案比较小而且建图更方便,所以我们直接从小往大枚举答案即可

之所以建图更方便,是因为如果我们从小向大枚举答案,那么原先建好的边是不用动的,因为原先的球一定要放,所以我们只需研究新来的球就可以了

而且还有一个好处,就是这样的话我们只需在残余网络上跑最大流,所以速度会更快一些?(口胡)

这里还有一个问题:如何建图?

直接从源点向新来的球连边,然后由新来的球向汇点连边,容量为1?

那这最大流不是要多少有多少的吗......

所以这样做显然不正确

正确的做法:把一个球拆成两个(设为x与y),然后由源点向x连边,容量为1,由y向汇点连边,容量为1,

接下来,我们找出所有满足与当前球编号和为完全平方数的球,将当前球的x点向那些球的y点连边,容量为1

然后每次在残余网络上跑最大流,如果最大流为0则说明需要新加一个柱子,加到柱子数超过给出的即结束

稍微解释一下这种做法的原因:我们把球拆成两个点以后,可以看做是一个球的上下两面,x表示与原先有的球相接,y表示在它上面放新的球的能力。

这样的话,我们把新来的x与原先合法的y相连后跑最大流,如果新的最大流不为0,说明这个新来的球能成功地放在一个原有的球上(这是因为最大流不为0说明了一条原来由某个y指向汇点的边本来流量是0,但现在流量变成了1而且保证了原有流量不变,这也就说明新来的球放在了一个柱上)

那么就自然是合法的了

然后是下一个问题(所以说这道题是好题,因为有很多个问题)

如何输出方案?

基于上面的解释,输出方案就变得简单了:我们从小往大枚举每个球,如果这个球还没被放在一个柱上则新开一个柱,然后顺着这个球的y点向下寻找,每找到一个没放下的点就放在这个柱上即可

可能说的有些抽象,具体解释一下:

我们从y点向外找边,是因为从y出发的边只要终点不是汇点那么一定是反向边!

如果反向边容量不为0,说明对应的正向边有1的流量,也就说明这个点之上被放上了一个点!

那么我们只需找出这个点,然后向下递归即可

注意找到一个点即可结束本层的寻找,因为一个球上最多只能放一个球啊

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
const int inf=0x3f3f3f3f;
struct Edge
{
int next;
int to;
int val;
}edge[2000005];
int head[10005];
bool used[10005];
int cur[10005];
int cnt=1;
int st,ed;
int n;
int dis[10005];
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
void add(int l,int r,int w)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
edge[cnt].val=w;
head[l]=cnt++;
}
int ide(int x)
{
return (x&1)?x+1:x-1;
}
bool bfs()
{
memcpy(cur,head,sizeof(head));
memset(dis,0,sizeof(dis));
queue <int> M;
M.push(st);
dis[st]=1;
while(!M.empty())
{
int u=M.front();
M.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(edge[i].val&&!dis[to])dis[to]=dis[u]+1,M.push(to);
}
}
return dis[ed];
}
int dfs(int x,int lim)
{
if(x==ed)return lim;
int ret=0;
for(int i=cur[x];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(edge[i].val&&dis[to]==dis[x]+1)
{
int temp=dfs(to,min(lim,edge[i].val));
if(temp)
{
lim-=temp;
ret+=temp;
edge[i].val-=temp;
edge[ide(i)].val+=temp;
if(!lim)break;
}
}
cur[x]=i;
}
return ret;
}
int dinic()
{
int ret=0;
while(bfs())ret+=dfs(st,inf);
return ret;
}
void print(int x)
{
used[x]=1;
printf("%d ",x);
for(int i=head[(x<<1)|1];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!edge[i].val||used[to>>1]||to==ed)continue;
print(to>>1);
break;
}
}
int main()
{
scanf("%d",&n);
init();
int tot;
st=0,ed=1;
int s=0;
for(tot=1;tot;tot++)
{
add(st,tot<<1,1);
add(tot<<1,st,0);
add((tot<<1)|1,ed,1);
add(ed,(tot<<1)|1,0);
for(int j=1;j*j<2*tot;j++)
{
if(j*j>tot)add(tot<<1,((j*j-tot)<<1)|1,1),add(((j*j-tot)<<1)|1,tot<<1,0);
}
if(!dinic())s++;
if(s>n)break;
}
printf("%d\n",tot-1);
for(int i=1;i<tot;i++)
{
if(used[i])continue;
print(i);
printf("\n");
}
return 0;
}

  

网络流24题——魔术球问题 luogu 2765的更多相关文章

  1. COGS396. [网络流24题]魔术球问题(简化版

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

  2. [luogu2765 网络流24题] 魔术球问题 (dinic最大流)

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

  3. Libre 6009 「网络流 24 题」软件补丁 / Luogu 2761 软件安装问题 (最短路径,位运算)

    Libre 6009 「网络流 24 题」软件补丁 / Luogu 2761 软件安装问题 (最短路径,位运算) Description T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放 ...

  4. Libre 6006 「网络流 24 题」试题库 / Luogu 2763 试题库问题 (网络流,最大流)

    Libre 6006 「网络流 24 题」试题库 / Luogu 2763 试题库问题 (网络流,最大流) Description 问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同 ...

  5. 网络流24题——试题库问题 luogu 2763

    题目描述看:这里 这是我们遇到的第一个要求输出方案的问题 考虑建图然后用最大流思想: 首先由源点向每一道试题连边,容量为1 然后由每一种试题类型向汇点连边,容量为需求量 最后由每一道试题向可能属于的试 ...

  6. 网络流24题——骑士共存问题 luogu 3355

    题目描述:这里 从这里开始,我们涉及到了一个新的问题:最小割问题 首先给出一些定义(本人根据定义自己口胡的): 一个流网络中的一个割是一个边集,使得割掉这些边集后源点与汇点不连通 而最小割问题就是一个 ...

  7. 网络流24题——数字梯形问题 luogu 4013

    题目描述:这里 极其裸的一道费用流问题 首先分析第一问,由于要求一个点只能经过一次,所以我们将梯形中的每一个点拆成两个点(记为入点和出点,顾名思义,入点用来承接上一行向这一行的边,出点用来向下一行连边 ...

  8. LOJ6003 - 「网络流 24 题」魔术球

    原题链接 Description 假设有根柱子,现要按下述规则在这根柱子中依次放入编号为的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法 ...

  9. LibreOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖

    6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...

随机推荐

  1. codeforces342B

    Xenia and Spies CodeForces - 342B Xenia the vigorous detective faced n (n ≥ 2) foreign spies lined u ...

  2. 【kafka】Java连接出现Connection refused: no further information的解决方法

    在Linux机器(ip:10.102.16.203)安装完kafka(参考:kafka的安装及使用),在windows上使用Java接口访问服务时(参考:Java实现Kafka的生产者.消费者),报异 ...

  3. bs4模块

    1.导入模块 from bs4 import BeautifulSoup 2.创建对象 Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它 ...

  4. BZOJ 1855 股票交易 (算竞进阶习题)

    单调队列优化dp dp真的是难..不看题解完全不知道状态转移方程QAQ 推出方程后发现是关于j,k独立的多项式,所以可以单调队列优化.. #include <bits/stdc++.h> ...

  5. Codeforces Round #543

    (比赛链接)[http://codeforces.com/contest/1120] A 给出一个长度为m的序列a 可以删除一些数 使得最后从没删的第一个数开始 每k个一截 截出的n个多重集合中 至少 ...

  6. [BJOI2019]勘破神机(斯特林数,数论)

    [BJOI2019]勘破神机(斯特林数,数论) 题面 洛谷 题解 先考虑\(m=2\)的情况. 显然方案数就是\(f_i=f_{i-1}+f_{i-2}\),即斐波那契数,虽然这里求出来是斐波那契的第 ...

  7. jira,Confluence 的JVM内存优化

    个人喜好,可能不是很适合大众 JIRA 修改setenv.sh,调整JVM为4096m [root@jira_confluence ~]# cd /app/atlassian/jira/bin/ [r ...

  8. 数据库基础——跟着【克里斯学SQL】哈哈。

    前言: 很多同学呀,对数据库的操作仅仅只能在于Navicat 等第三方可视化的工具上面!!!! 这是可怕的,数据库的操作十分的重要,甚至,他是程序最重要的部分. 面试经常问题, 了解那个数据? 写一个 ...

  9. Attention Model(注意力模型)思想初探

    1. Attention model简介 0x1:AM是什么 深度学习里的Attention model其实模拟的是人脑的注意力模型,举个例子来说,当我们观赏一幅画时,虽然我们可以看到整幅画的全貌,但 ...

  10. 那些年我们一起追逐的多线程(Thread、ThreadPool、委托异步调用、Task/TaskFactory、Parallerl、async和await)

    一. 背景 在刚接触开发的头几年里,说实话,根本不考虑多线程的这个问题,貌似那时候脑子里也有没有多线程的这个概念,所有的业务都是一个线程来处理,不考虑性能问题,当然也没有考虑多线程操作一条记录存在的并 ...