回家
题目描述
moreD城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由 2n 条地铁线路构成,组成了一个 n 纵 n 横的交通网。如下图所示,这 2n 条线路每条线路都包含 n 个车站,而每个车站都在一组纵横线路的交汇处。
出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有 m 个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行 1 站需要 2 分钟,而站内换乘需要步行 1 分钟。 你的最后一个作业就是算出,在不中途出站的前提下,从学校回家最快需要多少时间(等车时间忽略不计)。
输入格式
第一行有两个整数 n, m。接下去 m 行每行两个整数 x, y,表示第 x 条横向线路与第 y 条纵向线路的交汇站是站内换乘站。接下去一行是四个整数 x1, y1, x2, y2。表示从学校回家时,在第 x1条横向线路与第 y1 条纵向线路的交汇站上车,在第 x2 条横向线路与第 y2 条纵向线路的交汇站下车。
输出格式
仅一个整数表示在合理选择线路的情况下,回家所需要的最少时间。如果无法在不出站换车的情况下回家则输出-1。
输入样例
gohome1.in
6 9
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
1 1 4 6
gohome2.in
6 10
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
6 6
1 1 4 6
gohome3.in
2 1
1 2
1 1 2 2
输出样例
gohome1.out
27
gohome2.out
26
gohome3.out
5
数据范围
对于 的数据, = 0,=0
对于 的数据,
对于 的数据,
对于 的数据,
解题思路
题目所给的图:
我们按照输入的顺序给这些点标上号(包括起点和终点),共 个点。
设 ,表示点的数量。起点为 号节点,终点为 号节点。
我们可以把图分成两层,其中第 层为横向走,第 层为纵向走。
先考虑横向走。将所有点以横坐标为第 关键字,纵坐标为第 关键字从小到大排序。排完序后,判断相邻两个点的横坐标是否相同,如果相同,则在它们两个点之间连一条边权为 两点纵坐标之差的两倍 的双向边 。若可以连边 ,则说明从点 可以横向走到点 ,亦可以从点 横向走到点 。
图中可以连的边有:
边权分别为 。
纵向走同理。因为纵向走在第 层,节点编号不能与第 层相同,所以给第 层编号全部 。然后将所有点以纵坐标为第 关键字,横坐标为第 关键字从小到大排序。比较相邻两点纵坐标,连边。若可以连边 ,则说明从点 可以纵向走到点 ,也可以从点 纵向走到点 。
图中可以连的边有:
边权分别为 。
接下来在两层 表示同个节点的点 之间连一条权值为 的向边,表示可以在该点改变方向,用时为 。
注意起点和终点改变方向不需要 的时间,所以在 起点 与 起点 之间,终点 与 终点 之间连一条边权为 的双向边。
最后跑一遍起点到终点的最短路即是答案,时间复杂度为 。
完整的图:
参考代码
在此附上本人的 AC 代码,仅供参考,请勿抄袭:
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct Edge
{
int next,to,val;
}edge[2000010];
struct Node{
int x,y,id;
}a[2000010];
int cnt=0,head[2000010],n,m,dis[2000010],S,T;
queue<int> q;
bool vis[2000010];
void add(int from,int to,int val){
edge[++cnt].to=to;
edge[cnt].val=val;
edge[cnt].next=head[from];
head[from]=cnt;
}
void ins(int from,int to,int val){
add(from,to,val);add(to,from,val);
}
bool cmp1(Node a,Node b){
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
bool cmp2(Node a,Node b){
if(a.y==b.y)return a.x<b.x;
return a.y<b.y;
}
void spfa(){
memset(dis,0x3f3f3f3f,sizeof(dis));
dis[S]=0;
vis[S]=1;
q.push(S);
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to,val=edge[i].val;
if(dis[to]>dis[x]+val){
dis[to]=dis[x]+val;
if(!vis[to])vis[to]=1,q.push(to);
}
}
}
}
int main(){
n=read(),m=read();
S=m+1,T=m+2;
for(int i=1;i<=m+2;i++){
a[i].x=read(),a[i].y=read();
a[i].id=i;
}
sort(a+1,a+m+3,cmp1);
for(int i=1;i<m+2;i++)
if(a[i].x==a[i+1].x)ins(a[i].id,a[i+1].id,2*(a[i+1].y-a[i].y));
sort(a+1,a+m+3,cmp2);
for(int i=1;i<m+2;i++)
if(a[i].y==a[i+1].y)ins(a[i].id+m+2,a[i+1].id+m+2,2*(a[i+1].x-a[i].x));
for(int i=1;i<=m;i++)ins(i,i+m+2,1);
ins(m+1,m*2+3,0);ins(m+2,m*2+4,0);
spfa();
printf("%d\n",dis[T]==0x3f3f3f3f?-1:dis[T]);
}
——————————QAQ
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122201
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话