P3831 [SHOI2012]回家的路
分层图基础题,就是建图稍有麻烦

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
//P3831 [SHOI2012]回家的路 https://www.luogu.com.cn/problem/P3831
//一个网格,只能沿一个方向(横或纵)走
//某些交叉点可以改变方向
//沿一个方向走的时候,走一格花费两个时间,改变一次方向花费一个时间
//给出这些点,问网格中两点之间最短时间
//分层图,为每个可以改变方向的点(按照题目背景是换乘点),分别创建两个虚拟节点
//一个是横着走的,也就是走到这里只能继续横着走
//一个是纵列方向走
//然后,对于每一横行,依次从左往右把这些在一行的点连边
//纵列也是如此
//然后每一个换乘点,横纵方向的两个点之间连一个时间为 1 的点,表示换成
//起点和终点也看作换乘点,这样方便我们连边
//只不过它们的横纵方向的两点间边权为 0 ,因为在起点并不存在换乘的问题
//1-m 是横列换乘点的编号
//m+1 是起点的横列
//m+2 是终点的横列
//m+3-2*m+2 是纵列换乘点的编号
//2*m+3 起点纵列
//2*m+4 终点纵列
//1-m 分别和 m+2-2*m+2 连权值为 1 的边
//m+1 和 2*m+3 以及 m+2 和 2*m+4 连权值为 0 的边
//以 m+1 或 2*m+3 任意一个为虚构的图中的起点
//以 m+2 或 2*m+4 任意一个为虚构的图中的终点
//设横列编号为 id 则对应的纵列编号为 id+m+2
//数组尽量开大,一开始算错 WA 了
struct data{
int x,y,id;
}a[100009];
int dis[200009],in[200009];
int fir[200009],nex[700006],to[700006],w[700006],tot;
int heap[200009],size;
inline int cmpx(data aa,data aaa){return aa.x==aaa.x?aa.y<aaa.y:aa.x<aaa.x;}
inline int cmpy(data aa,data aaa){return aa.y==aaa.y?aa.x<aaa.x:aa.y<aaa.y;}
inline void add(int u,int v,int len){
to[++tot]=v;w[tot]=len;
nex[tot]=fir[u];fir[u]=tot;
}
inline void link(int u,int v,int len){
add(u,v,len);add(v,u,len);
}
inline void push(int x){
heap[++size]=x;
reg int i=size,fa;
while(i>1){
fa=i>>1;
if(dis[heap[fa]]<=dis[heap[i]]) return;
std::swap(heap[fa],heap[i]);i=fa;
}
}
inline int pop(){
int ret=heap[1];heap[1]=heap[size--];
int i=1,ls,rs;
while((i<<1)<=size){
ls=i<<1;rs=ls|1;
if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
if(dis[heap[ls]]>=dis[heap[i]]) break;
std::swap(heap[i],heap[ls]);i=ls;
}
return ret;
}
inline void dij(int start){
std::memset(dis,0x3f,sizeof dis);dis[start]=0;
push(start);in[start]=1;
while(size){
reg int u=pop(),v;in[u]=0;
for(reg int i=fir[u];i;i=nex[i]){
v=to[i];
if(dis[v]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
if(!in[v]) push(v),in[v]=1;
}
}
}
}
inline void build(int m){
std::sort(a+1,a+1+m+2,cmpx);
for(reg int i=1;i<=m+2;){
int now_x=a[i].x;
for(i++;i<=m+2&&a[i].x==now_x;i++) link(a[i].id,a[i-1].id,(a[i].y-a[i-1].y)<<1);
}
std::sort(a+1,a+1+m+2,cmpy);
for(reg int i=1;i<=m+2;){
int now_y=a[i].y;
for(i++;i<=m+2&&a[i].y==now_y;i++) link(a[i].id+m+2,a[i-1].id+m+2,(a[i].x-a[i-1].x)<<1);
}
for(reg int i=1;i<=m;i++) link(i,i+m+2,1);
link(m+1,2*m+3,0);link(m+2,2*m+4,0);
}
int main(){
read();int m=read();
for(reg int i=1;i<=m+2;i++) a[i].x=read(),a[i].y=read(),a[i].id=i;
build(m);
dij(m+1);
std::printf("%d",dis[2*m+4]==0x3f3f3f3f?-1:dis[2*m+4]);
// EN;EN;
// for(reg int i=1;i<=m*2+4;i++){
// std::printf("%d : ",i);
// for(reg int j=fir[i];j;j=nex[j]) std::printf("%d ",to[j]);
// EN;
// }
return 0;
}
P3831 [SHOI2012]回家的路的更多相关文章
- 题解 P3831 [SHOI2012]回家的路
什么叫分层图最短路,我不会/kk 感觉自己做法和其他题解不大一样所以过来发篇题解了. 未刻意卡常拿下最优解 题目大意 就是说给你一个 \(n \times n\) 的网格图和 \(m\) 个可换乘点, ...
- [SHOI2012]回家的路
题目背景 SHOI2012 D2T1 题目描述 2046 年 OI 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由2n2n条地铁线路构成,组成了一个nn纵nn横的交通网.如 ...
- [SHOI2012]回家的路 最短路
---题面--- 题解: 吐槽:找了好久的错,换了n种方法,重构一次代码,,,, 最后发现,,, 数组开小了,其实一开始尝试开大了数组,但唯独没有尝试开大手写队列的数组.... 思路: 有两种方法,这 ...
- Bzoj 2834: 回家的路 dijkstra,堆优化,分层图,最短路
2834: 回家的路 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 62 Solved: 38[Submit][Status][Discuss] D ...
- 分层图最短路【bzoj2834】: 回家的路
分层图最短路[bzoj2834]: 回家的路 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2834 这道题难在建边. 自己写的时候想到了 ...
- bzoj 2834: 回家的路
题目 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser DCOI Logout 捐赠本站 Notice:1 ...
- 洛谷P3831 回家的路
题目背景 SHOI2012 D2T1 题目描述 \(2046\) 年 \(OI\) 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由\(2n\)条地铁线路构成,组成了一个\( ...
- BZOJ.2834.回家的路(最短路Dijkstra 拆点)
题目链接 对于相邻的.处在同在一行或一列的车站连边,然后用dis[x][0/1](或者拆点)分别表示之前是从横边还是竖边到x的,跑最短路. 我选择拆点.. //13028kb 604ms #inclu ...
- 解题:SHOI 2012 回家的路
题面 完了,做的时候已经想不起来分层图这个东西了QAQ 对于这种“多种”路径加中转站的题,还有那种有若干次“特殊能力”的题,都可以考虑用分层图来做 显然只需要记录所有的中转站+起点终点,然后拆出横竖两 ...
随机推荐
- C语言实现顺序表(顺序存储结构)
顺序表(顺序存储结构)及初始化过程详解 顺序表,全名顺序存储结构,是线性表的一种.通过<线性表>一节的学习我们知道,线性表用于存储逻辑关系为"一对一"的数据,顺序表自然 ...
- "强调内容"组件:<em> —— 快应用组件库H-UI
 <import name="em" src="../Common/ui/h-ui/text/c_tag_i"></import> & ...
- Python爬虫系列(二):requests基础
1.发送请求: import requests # 获取数据#r是一个 response 对象.包含请求返回的内容r = requests.get('https://github.com/timeli ...
- 小程序以及H5页面上IphoneX底部安全区域小黑条适配问题
背景 公司项目开发中,发现iPhoneX上吸底元素存在被小黑条遮挡的问题 原因 在苹果 iPhoneX .iPhone XR等机型上,物理Home键被取消,改为底部小黑条替代home键功能,从而导致吸 ...
- CNVD
漏洞编号 漏洞名称 漏洞积分 奖励时间 CNVD-2020-15798 中国平乐县委员会组织部网站管理系统登录存在弱口令漏洞 1.0 2020-03-09 09:58:46.0 CNVD-2020-1 ...
- ClassLoader类加载器浅见
类加载器 类加载器,它拿到.class文件,它会把他拆成两部分,将static数据转换成方法区的数据结构,然后把他放在了方法区之中. 然后在堆里面建一个类对象(Class,它可以用来实例化对象),然后 ...
- AJ学IOS 之CoreLocation反地理编码小Demo输入经纬度得到城市
AJ分享,必须精品 一:效果 输入经纬度,可以得到相应的地名 二:思路 跟地里编码差不多 1.获取用户输入的经纬度 2.根据用户输入的经纬度创建CLLocation对象 3.根据CLLocation对 ...
- ASE课程总结 by 张葳
本期ASE课程分为两个阶段,第一阶段的personal project与第二阶段的team project,其中,第一阶段旨在锻炼我们个人的问题解决能力和编程能力,第二阶段则锻炼主要我们的管理能力,合 ...
- Java集合:ArrayList (JDK1.8 源码解读)
ArrayList ArrayList几乎是每个java开发者最常用也是最熟悉的集合,看到ArrayList这个名字就知道,它必然是以数组方式实现的集合 关注点 说一下ArrayList的几个特点,也 ...
- Mac安装多版本JDK
0. 配置JDK环境 安装完成之后,配置.bash_profile文件 使用source ./bash_profile激活 2. 如何切换默认的jdk? 使用java -version就可以看默认版本 ...