Libre 6003 「网络流 24 题」魔术球 (网络流,最大流)
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 题」魔术球 (网络流,最大流)的更多相关文章
- 2018.10.14 loj#6003. 「网络流 24 题」魔术球(最大流)
传送门 网络流好题. 这道题可以动态建图. 不难想到把每个球iii都拆点成i1i_1i1和i2i_2i2,每次连边(s,i1),(i2,t)(s,i_1),(i_2,t)(s,i1),(i2, ...
- LibreOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖
6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...
- [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流
#6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...
- LOJ6003 - 「网络流 24 题」魔术球
原题链接 Description 假设有根柱子,现要按下述规则在这根柱子中依次放入编号为的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法 ...
- 【刷题】LOJ 6003 「网络流 24 题」魔术球
题目描述 假设有 \(n\) 根柱子,现要按下述规则在这 \(n\) 根柱子中依次放入编号为 \(1, 2, 3, 4, \cdots\) 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任 ...
- [cogs396] [网络流24题#4] 魔术球 [网络流,最大流,最小路径覆盖]
本题枚举每多一个球需要多少个柱子,可以边加边边计算,每次只需要判断$i-Dinic()$即可:特别注意边界. #include <iostream> #include <algori ...
- Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)
Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...
- Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)
Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...
- LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流
#6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
随机推荐
- Fiddler无法抓取某些APP的HTTPS请求,无解!!!
遇到有些APP的HTTPS请求无法抓取!错误提示: !SecureClientPipeDirect failed: System.Security.Authentication.Authenticat ...
- C# HtmlAgilityPack和AngleSharp 解析HTML
C# HtmlAgilityPack和AngleSharp 解析HTML by:wgscd date:2018-1-17 HtmlAgilityPack 有点是只有一个单独DLL.AngleShar ...
- [APIO2015]巴厘岛的雕塑[按位贪心+dp]
题意 给你长度为 \(n\) 的序列,要求分成 \(k\) 段连续非空的区间,求所有区间和的 \(or\) 最小值. 分析 定义 \(f_{i,j}\) 表示前 \(i\) 个点分成 \(j\) 段的 ...
- KVM虚拟机管理——虚拟机创建和操作系统安装
1. 概述2. 交互式安装2.1 图形化-本地安装2.1.1 图形化本地CDROM安装2.2.2 图形化本地镜像安装2.2 命令行-本地安装2.2.1 命令行CDROM安装2.3 图形化-网络安装2. ...
- 杂谈---小故事小道理,面试中的小技巧(NO.2)
本篇是接着上一篇面试随笔的,上一次有猿友反应写的有些“扯淡”,LZ思来想去最大的原因可能是由于上一章写的全是一些大忌,既然是大忌,那么在现实当中发生的概率还是相对较小的,大部分人还是很少在面试中犯如此 ...
- Ing_制作在线QQ
制作在线QQ的具体步骤 1.首先登录到http://is.qq.com/webpresence/code.shtml 网站2.选择风格3.填写相关数据4.生成网页代码5.复制代码到“写字板”,另存文件 ...
- [翻译]:Cinemachine 官方文档(0)
目录 Overview : Installation and Getting Started :安装并开始 User Guide :用户指南 What is Cinemachine? : 什么是Cin ...
- CocoStuff—基于Deeplab训练数据的标定工具【二、用已提供的标注数据跑通项目】
一.说明 本文为系列博客第二篇,主要讲述笔者在使用该团队提供已经标注好的COCO数据集进行训练的过程. 由于在windows中编译Caffe和Deeplab特别的麻烦,笔者并没有去探索,后续可能会去尝 ...
- PowerDesigner数据库设计实用技巧
欢迎大家补充,谢谢! 1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对多或多对一的 ...
- Daily Scrum 10.20
今天进行了团队第一次scrum meeting,在这次会议中,我们针对NABC模型以及开发前期的工作进行了探讨. 第一次会议 主要内容如下: 为了大家接下来几周的开发效率,需要共同商量团队的一些规则 ...