Libre 6003 「网络流 24 题」魔术球 (网络流,最大流)

Description

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球。

(1)每次只能在某根柱子的最上面放球。

(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可 放11个球。

´编程任务:

对于给定的n,计算在 n根柱子上最多能放多少个球。

Input

第1 行有 1个正整数n,表示柱子数。

Output

第一行是球数。接下来的 n行,每行是一根柱子上的球的编号。

Sample Input

4

Sample Output

11

1 8

2 7 9

3 6 10

4 5 11

Http

Libre:https://loj.ac/problem/6003

Source

网络流

解决思路

这道题不好想到是网络流的题目。

博主觉得自己的解释有些问题,等博主想清楚了再写吧。。。(2018.1.2 Update)

我们从小到大依次枚举最大能放入的球的大小。对于每一个球,我们将其拆成两个,一个入点一个出点。从源点向入点连一条流量为1的边,从出点向汇点也连一条流量为1的边,这样是为了保证一个球要么上面或下面没有球要么每一面至多有一个球。当我们在枚举球x时,从1到x-1循环看一看有那些球满足它与x的和是完全平方数。如果是,则在那个球的出点与x的入点之间连一条流量为1的边,同样是为了保证只有一个球。

通过上面这样的模型转换,我们就把题目变成了求最少路径覆盖。关于最少路径覆盖,可以到我的这一篇文章查看

然后我们就可以每一次加入一个数即其相应的边,跑一边最大流求出最小路径覆盖,如果当前的路径覆盖数大于我们输入的柱子数,则说明答案是当前-1.

需要注意的是因为我们是逐渐加边的,即每一次其实是在上一次的残量网络上加边,所以统计路径覆盖数时不要重新统计,而是在原来的基础上进行统计。

至于如何输出一组方案呢?我们把图全部重新建一遍,再跑最大流,然后从小到大扫描每一个数,若发现该数还未访问,则从该数出发,寻找它的流流向了哪个点,循环输出,直到某个点的出点是到汇点,把这条路径上的点全部打上标记。这样对比输出即可。

另:这里使用Dinic实现最大流,关于Dinic算法,请移步我的这篇文章

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std; const int maxN=5000;
const int maxM=100001;
const int inf=2147483647; class Edge
{
public:
int u,v,flow;
}; int n,m;
int cnt=-1;
int Head[maxN];
int Next[maxM];
Edge E[maxM];
int depth[maxN];
int cur[maxN];
int Q[maxM];
bool vis[maxN]; void Add_Edge(int u,int v,int flow);
bool bfs();
int dfs(int u,int flow); int main()//笔者这里用0代表源点,1代表汇点;而对于每一个点u,其拆点后的入点为u*2,出点为u*2+1
{
int sum;
memset(Head,-1,sizeof(Head));
scanf("%d",&sum);
int Ans=0;
n=0;
do//从1开始加点和加边
{
n++;
Ans++;//注意这里,每一次开始时,加入一个数相当于要多一条路径,因为我们还没有把其放入任何以前的路径中
Add_Edge(0,n*2,1);//先连上n与汇点和n与源点
Add_Edge(n*2+1,1,1);
for (int i=1;i<n;i++)//循环扫描以前的数,若满足和为完全平方数,则连边
if (sqrt(n+i)==(int)(sqrt(n+i)))
Add_Edge(i*2,n*2+1,1);
while (bfs())
{
for (int i=0;i<=n*2+1;i++)
cur[i]=Head[i];
while (int di=dfs(0,inf))
Ans-=di;//注意这Ans是减,因为当增广出一条新的路径时,说明原路径数减1
}
if (Ans>sum)//若发现此时路径数已经比柱子数大了,则说明前一个是答案,退出并减一
{
n--;
break;
}
}
while (1);
cout<<n<<endl;
for (int i=0;i<=cnt;i++)//重新建图
if ((E[i].u<E[i].v)||(E[i].v==1))
E[i].flow=1;
else
E[i].flow=0;
Ans=0;//再跑一边最大流
while (bfs())
{
for (int i=0;i<=n*2+1;i++)
cur[i]=Head[i];
while (int di=dfs(0,inf))
Ans+=di;
}
memset(vis,0,sizeof(vis));//输出方案
for (int i=1;i<=n;i++)
{
if (vis[i]==1)
continue;
int now=i;
bool get=0;
do
{
cout<<now<<' ';
vis[now]=1;
get=0;
for (int i=Head[now*2];i!=-1;i=Next[i])
if ((E[i].v%2!=0)&&(E[i].flow==0))
{
get=1;
now=E[i].v/2;
break;
}
}
while (get==1);
cout<<endl;
}
return 0;
} void Add_Edge(int u,int v,int flow)
{
cnt++;
Next[cnt]=Head[u];
Head[u]=cnt;
E[cnt].u=u;
E[cnt].v=v;
E[cnt].flow=flow; cnt++;
Next[cnt]=Head[v];
Head[v]=cnt;
E[cnt].u=v;
E[cnt].v=u;
E[cnt].flow=0;
} bool bfs()
{
memset(depth,-1,sizeof(depth));
int h=1,t=0;
Q[1]=0;
depth[0]=1;
do
{
t++;
int u=Q[t];
for (int i=Head[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==-1)&&(E[i].flow>0))
{
depth[v]=depth[u]+1;
h++;
Q[h]=v;
}
}
}
while (h!=t);
if (depth[1]==-1)
return 0;
return 1;
} int dfs(int u,int flow)
{
if (u==1)
return flow;
for (int &i=cur[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==depth[u]+1)&&(E[i].flow>0))
{
int di=dfs(v,min(flow,E[i].flow));
if (di>0)
{
E[i].flow-=di;
E[i^1].flow+=di;
return di;
}
}
}
return 0;
}

Libre 6003 「网络流 24 题」魔术球 (网络流,最大流)的更多相关文章

  1. 2018.10.14 loj#6003. 「网络流 24 题」魔术球(最大流)

    传送门 网络流好题. 这道题可以动态建图. 不难想到把每个球iii都拆点成i1i_1i1​和i2i_2i2​,每次连边(s,i1),(i2,t)(s,i_1),(i_2,t)(s,i1​),(i2​, ...

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

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

  3. [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

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

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

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

  5. 【刷题】LOJ 6003 「网络流 24 题」魔术球

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

  6. [cogs396] [网络流24题#4] 魔术球 [网络流,最大流,最小路径覆盖]

    本题枚举每多一个球需要多少个柱子,可以边加边边计算,每次只需要判断$i-Dinic()$即可:特别注意边界. #include <iostream> #include <algori ...

  7. Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)

    Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...

  8. Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)

    Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...

  9. LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流

    #6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

随机推荐

  1. 2017-2018-2 20155231《网络对抗技术》实验五: MSF基础应用

    2017-2018-2 20155231<网络对抗技术>实验五: MSF基础应用 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 实验内容 (1)各种搜索技巧的应用 比如IP2L ...

  2. 20155236范晨歌_Web安全基础实践

    20155236范晨歌_Web安全基础实践 目录 实践目标 WebGoat BurpSuite Injection Flaws Cross-Site Scripting (XSS) 总结 实践目标 ( ...

  3. 2017-2018-1 20155320 嵌入式C语言——时钟

    2017-2018-1 20155320 嵌入式C语言--时钟 要求: 在作业本上完成附图作业,要认真看题目要求. 提交作业截图 作弊本学期成绩清零(有雷同的,不管是给别人传答案,还是找别人要答案都清 ...

  4. 【来龙去脉系列】AutoMapper一款自动映射框架

    前言 通常在一个应用程序中,我们开发人员会在两个不同的类型对象之间传输数据,通常我们会用DTOs(数据传输对象),View Models(视图模型),或者直接是一些从一个service或者Web AP ...

  5. C#_Stream

    IO操作基本上需要用到Stream相关的子类,因此这类问题在CSDN问得也是比较多.其实对于Stream来说,操作起来比较简单,只要对细节的处理稍微注意一下,相信在使用它的时候也会得心应手. 对于St ...

  6. Python包下载超时问题解决

    pip下载模块慢解决办法 由于pip安装默认的访问地址为 http://pypi.python.org/simple/经常会有网络不稳定和速度慢的现象,出现timeout报错,因此可以改为访问国内的地 ...

  7. jumpserver部署

    1.部署环境.安装依赖包 # yum install git python-pip mysql-devel gcc automake autoconf python-devel vim sshpass ...

  8. linux一切皆文件之块设备文件(四)

    一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.块设备是 ...

  9. LeetCode-97.交错字符串

    给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的. 示例 1: 输入: s1 = "aabcc", s2 = "dbbca&quo ...

  10. 火狐浏览器之伪造IP地址

    前言: 前段时间,测试过程中需要伪造来源IP地址,百思不得其解,因而发现火狐浏览器的这个Modify Headers插件,十分好用,推荐给大家. 步骤: 1.安装插件Modify Headers 进入 ...