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 对于这种“多种”路径加中转站的题,还有那种有若干次“特殊能力”的题,都可以考虑用分层图来做 显然只需要记录所有的中转站+起点终点,然后拆出横竖两 ...
随机推荐
- ThinkPHP3.2.3集成微信分享JS-SDK实践
先来看看微信分享效果:在没有集成微信分享js-sdk前是这样的:没有摘要,缩略图任意抓取正文图片 在集成微信分享js-sdk后是这样的:标题,摘要,缩略图自定义 一.下载微信SDK开发包下载地址:ht ...
- 04 jmeter使用方式3种
1.手工添加配置元件编写 2.jmeter+badboy 工具录制---不建议使用 3.设置代理服务器(jmeter添加‘非测试元件-http代理服务器’,再添加一个线程组用来保留代理抓取的url,设 ...
- linux中操作k8s的基本命令-更新中
linux中操作k8s的基本命令 最近工作中使用到了k8s,那么就来总结下平时使用到的基本的命令 获取某个namespace下的pod 获取某个namespace下的pod,展示出ip和pod信息 查 ...
- cmake cpack 安装打包程序
//set(CPACK_GENERATOR "TGZ") 7Z(.7z) 7Zzip(.7z) TBZ2(tar.bz2) TGZ(.tar.gz) TXZ(.tar.xz) TZ ...
- 一个spring 基本知识的微博(怎么加载多个xml、多个property文件、aop配置、监视器)
http://blog.sina.com.cn/s/blog_61c5866d0100ev44.html
- 数据结构和算法(Golang实现)(12)常见数据结构-链表
链表 讲数据结构就离不开讲链表.因为数据结构是用来组织数据的,如何将一个数据关联到另外一个数据呢?链表可以将数据和数据之间关联起来,从一个数据指向另外一个数据. 一.链表 定义: 链表由一个个数据节点 ...
- 2020年iOS进阶面试题总结(一)
准备找工作的你,可以看看,复习复习!! 1.说一下OC的反射机制 在动态运行下我们可以构建任何一个类,然后我们通过这个类知道这个类的所有的属性和方法,并且如果我们创建一个对象,我们也可以通过对象找到这 ...
- char类型及ASCII码之间比较
在JAVA中,char类型可以直接运算,char在ASCII等字符编码表中有对应的数值对char类型字符运行时,直接当做ASCII表对应的整数来对待 参考 https://blog.csdn.net/ ...
- 食物链 POJ - 1182 (并查集的两种写法)
这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃 ...
- MySQL笔记总结-TCL语言
TCL语言 事务 一.含义 事务控制语言 Transaction Control Language 事务:一条或多条sql语句组成一个执行单位,一组sql语句要么都执行要么都不执行 二.特点(ACID ...