回家

传送门 @TOC

题目描述

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

数据范围

对于 10%10\%的数据, nn = 0,mm=0

对于 30%30\%的数据, n50,m1000n \leq 50, m \leq 1000

对于 60%60\%的数据, n500,m2000n \leq 500, m \leq 2000

对于 100%100\%的数据,n20000,m100000n \leq 20000, m \leq 100000

解题思路

题目所给的图:

在这里插入图片描述

我们按照输入的顺序给这些点标上号(包括起点和终点),共 m+2m + 2 个点。

在这里插入图片描述

n=m+2n = m + 2,表示点的数量。起点为 1010 号节点,终点为 1111 号节点。

我们可以把图分成两层,其中第 11 层为横向走,第 22 层为纵向走。

先考虑横向走。将所有点以横坐标为第 11 关键字,纵坐标为第 22 关键字从小到大排序。排完序后,判断相邻两个点的横坐标是否相同,如果相同,则在它们两个点之间连一条边权为 两点纵坐标之差的两倍 的双向边 。若可以连边 uvu \leftrightarrow v,则说明从点 uu 可以横向走到点 vv,亦可以从点 vv 横向走到点 uu

图中可以连的边有:

121 \leftrightarrow 2

4114 \leftrightarrow 11

565 \leftrightarrow 6

787 \leftrightarrow 8

898 \leftrightarrow 9

边权分别为 8,4,8,4,28,4,8,4,2

纵向走同理。因为纵向走在第 22 层,节点编号不能与第 11 层相同,所以给第 22 层编号全部 +n+n。然后将所有点以纵坐标为第 11 关键字,横坐标为第 22 关键字从小到大排序。比较相邻两点纵坐标,连边。若可以连边 uvu \leftrightarrow v,则说明从点 uu 可以纵向走到点 vv,也可以从点 vv 纵向走到点 uu

图中可以连的边有:

10+111+1110+11 \leftrightarrow 1+11

1+117+111+11 \leftrightarrow 7+11

3+115+113+11 \leftrightarrow 5+11

4+119+114+11 \leftrightarrow 9+11

11+116+1111+11 \leftrightarrow 6+11

边权分别为 2,8,4,4,22,8,4,4,2

接下来在两层 表示同个节点的点 之间连一条权值为 11向边,表示可以在该点改变方向,用时为 11

注意起点和终点改变方向不需要 11 的时间,所以在 起点 与 起点 +n+n 之间,终点 与 终点 +n+n 之间连一条边权为 00 的双向边。

最后跑一遍起点到终点的最短路即是答案,时间复杂度为 O(mlogm)O(m\log m)

完整的图:

在这里插入图片描述

参考代码

在此附上本人的 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

posted @ 2021-04-23 19:02  蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  来源