luogu_3645: 雅加达的摩天楼
雅加达的摩天楼
题意描述:
- 有\(N\)座摩天楼,从左到右依次编号为\(0\)到\(N-1\)。
- 有\(M\)个信息传递员,编号依次为\(0\)到\(M-1\)。编号为i的传递员最初在编号为\(B_i\)的摩天楼,邮递员可以在摩天楼之间跳跃(向前或者向后),编号为\(i\)的传递员跳跃能力为\(P_i\)。
- 当传递员到达一个摩天楼他可以执行两种操作
- 1: 跳跃到其他摩天楼上。
- 2: 将消息传递给当前摩天楼的其他传递员。
- 最终要将编号为\(0\)的摩天楼信息传递到编号为\(1\)的摩天楼地方。
输入格式:
- 第一行输入\(N\)和\(M\)。\((1\leq n \leq 3*10^4,1\leq m \leq 3*10^4)\)
- 接下来第\(2\)到\(M+1\),每行包含两个整数\(B_i\)和\(P_i\)。
输出格式:
- 输出一行,表示最小步数,如果无法到达则输出\(-1\)。
解题思路:
- 分析完题目后可以想到是最短路,对于每一个传递员都可以跳到别处,可以以此建立起点和终点,边权为1。
- 考虑暴力加边的做法,但是如果\(p\)很小的时候,最坏情况下有\(n^2\)条边,任何最短路算法都无法通过。
- 优化建图,采用分块的思想: 将\(n\)点合并为\(\sqrt{n}\)个块
- 对于\(P_i\leq\sqrt{n}\)的传递员:
- 对于某一栋摩天大楼,就把他从一个点转化为一栋真的摩天大楼。
- 对于每栋楼建\(\sqrt{n}\)层,每层有\(n\)个点,第一层代表\(p=1\)的走法,第二层代表\(p=2\)的走法,....。其中第\(0\)代表原先的那个点。
- 然后暴力加边。第\(i\)层代表\(P=i\)的情况,间距为\(i\)的点相互连长度为\(1\)的边。再把这些辅助点全部连向底边。
- 对于每个\(P_i>\sqrt{n}\)的点向其能达到的所有点的第\(0\)层加边。
- 对于\(P_i\leq\sqrt{n}\)的传递员:
- 总边数不会超过\(N\sqrt{N}\)。
- 建图完毕,跑最短路。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (3e4 + 10)*500;
const int maxm = (3e4 + 10)*500;
int n, m;
int s, t; //起点和终点
int B[maxn], P[maxn]; //起始于B, 跳跃能力为P
int block;
int head[maxn], nex[maxn<<1], ver[maxn<<1], edge[maxn<<1], tot;
inline void add_edge(int x, int y, int z)
{
ver[++tot] = y; edge[tot] = z;
nex[tot] = head[x]; head[x] = tot;
}
inline int get_block(int x, int y){
return x*n + y;
}
int dist[maxn];
bool v[maxn];
void SPFA()
{
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0; queue<int> q;
q.push(s); v[s] = 1;
while(q.size())
{
int x = q.front(); q.pop();
v[x] = 0;
for(int i = head[x]; i; i = nex[i])
{
int y = ver[i], z = edge[i];
if(dist[y] > dist[x] + z)
{
dist[y] = dist[x] + z;
if(!v[y])
{
q.push(y);
v[y] = 1;
}
}
}
}
printf("%d\n", dist[t] == 0x3f3f3f3f ? -1 : dist[t]);
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1, x, y; i <= m; i++)
{
scanf("%d%d", &x, &y);
B[i] = x + 1, P[i] = y;
}
//起始位置 终止位置 块的大小
s = B[1], t = B[2]; block = min((int)sqrt(n), 100);
//每一个点转化为一栋楼, 有sqrt(n)层
for(int i = 1; i <= block; i++)
for(int j = 1; j <= n; j++)
{
add_edge(get_block(i, j), j, 0); //楼底到每一层连边
if(j <= n - i) //j条一次跳出范围了
{
//每一层间隔为i的点 跳一次边权为1
add_edge(get_block(i,j), get_block(i,j)+i, 1);
add_edge(get_block(i,j)+i, get_block(i,j), 1);
}
}
for(int i = 1; i <= m; i++) //考虑每一个doge的跳跃能力
{
// 对于每一个传递员, 从楼底到Pi层对应连边
if(P[i] <= block)
add_edge(B[i], get_block(P[i], B[i]), 0);
else
{ //如果大于一个块了 那就暴力加边 因为有sqrt个块 所以加sqrt条边
for(int j = 1; B[i] + j * P[i] <= n; j++)
add_edge(B[i], B[i] + j*P[i], j); //向前跳
for(int j = 1; B[i] - j * P[i] >= 1; j++)
add_edge(B[i], B[i] - j*P[i], j); //向后跳
} //这里最大可能加N*sqrt(N)条边
} SPFA(); //优化后边数有 N*sqrt(N)的规模
return 0;
}
luogu_3645: 雅加达的摩天楼的更多相关文章
- bzoj 4070 [Apio2015]雅加达的摩天楼 Dijkstra+建图
[Apio2015]雅加达的摩天楼 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 644 Solved: 238[Submit][Status][D ...
- 【BZOJ4070】[Apio2015]雅加达的摩天楼 set+最短路
[BZOJ4070][Apio2015]雅加达的摩天楼 Description 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼 ...
- BZOJ 4070:[APIO2015]雅加达的摩天楼 最短路
4070: [Apio2015]雅加达的摩天楼 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 464 Solved: 164[Submit][Sta ...
- 【题解】P3645 [APIO2015]雅加达的摩天楼(分层图最短路)
[题解]P3645 [APIO2015]雅加达的摩天楼(分层图最短路) 感觉分层图是个很灵活的东西 直接连边的话,边数是\(O(n^2)\)的过不去 然而我们有一个优化的办法,可以建一个新图\(G=( ...
- luogu P3645 [APIO2015]雅加达的摩天楼 分块 根号分治
LINK:雅加达的摩天楼 容易想到设\(f_{i,j}\)表示第i个\(doge\)在第j层楼的最小步数. 转移显然是bfs.值得一提的是把初始某层的\(doge\)加入队列 然后转移边权全为1不需要 ...
- 4070: [Apio2015]雅加达的摩天楼
Description 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼外,雅加达市没有其他摩天楼. 有 M 只叫做 “do ...
- [APIO2015]雅加达的摩天楼
Description 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼外,雅加达市没有其他摩天楼. 有 M 只叫做 " ...
- 【bzoj4070】[Apio2015]雅加达的摩天楼 set+堆优化Dijkstra
题目描述 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼外,雅加达市没有其他摩天楼. 有 M 只叫做 “doge” 的神秘生物 ...
- 洛谷P3645 [APIO2015]雅加达的摩天楼
题目描述 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N − 1.除了这 NN 座摩天楼外,雅加达市没有其他摩天楼. 有 M 只叫做 “doge” 的神 ...
随机推荐
- MQTT v5.0------SUBSCRIBE 报文
SUBSCRIBE 报文 固定报头: 剩余长度字段 表示可变报头的长度加上有效载荷的长度,被编码为变长字节整数. 可变报头 SUBSCRIBE报文可变报头按顺序包含以下字段:报文标识符(Packet ...
- 设计模式之(六)原型模式(ProtoType)
认识原型模式 原型模式是比较简单的设计模式.废话不多说,直接看定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.通过实例指定种类,种类就是初始化的类,然后通过拷贝创建对象.先展示一个 ...
- Devops K8s
公司在组建Devops团队,base在上海 徐家汇.具体职位有Devops工程师和K8s工程师. 有意者请私信.
- vue中的混入
数据对象合并 数据对象在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先 var mixin = { data() { return { msg_mixins: 'mixin ...
- QTGraphics-View拖拽以及鼠标指针操作
因为QGraphicsView继承自QWidget,它也提供了像QWidget那样的拖拽功能. 另外,为了方便,Graphics View框架也为场景以及每个item提供拖拽支持.当视图接收到拖拽事件 ...
- 怎么解决前端线上Bug
有一种八阿哥(Bug),叫"在我电脑上是好的呀". 有一种解决方式,叫"你去好好排查一下你自己的代码". 有一种控诉,叫"这绝不是后端的问题" ...
- MySQL与Oracle的隔离级别
一.事务和隔离级别 事务的概念:事务是把对数据库的一系列操作都看做一个整体,要么全部成功,要么全部失败,利用事务我们可以保证数据库的完整性,事务具有原子性. 隔离级别:隔离级别定义了事务与事务之间的隔 ...
- Linux chage命令详解
原文 chage命令用于密码实效管理,该是用来修改帐号和密码的有效期限,接下来通过本文给大家介绍Linux chage命令相关知识,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧 lin ...
- 【TCP】TCP三次握手与四次挥手
一.TCP三次握手 第一次握手:Client 将标志位 SYN=1 ,随机产生一个值 seq=J ,并将该数据包发送给 Server .此时,Client 进入SYN_SENT 状态,等待 Serve ...
- 将linux和uboot集成到Android编译框架中
span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...