回家的路
时间限制:1s 空间限制:512MB
输入文件:gohome.in 输出文件:gohome.out
题目描述
2046 年 OI 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由2n条地铁线路构成,组成了一个nn纵nn横的交通网。如下图所示,这2n2n条线路每条线路都包含nn个车站,而每个车站都在一组纵横线路的交汇处。 出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有mm个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行 1 站需要 2 分钟,而站内换乘需要步行 1 分钟。Serenade 想要知道,在不中途出站的前提下,他从学校回家最快需要多少时间(等车时间忽略不计)。
输入格式
第一行有两个整数n,m。
接下去m行每行两个整数x,y,
表示第x条横向线路与第y条纵向线路的交汇站是站内换乘站。
接下去一行是四个整数x1,y1,x2,y2。表示 Serenade 从学校回家时,在第 x1条横向线路与第y1条纵向线路的交汇站上车,在第x2条横向线路与第y2条纵向线路的交汇站下车。
输出格式
只有一行,即 Serenade 在合理选择线路的情况下,回家所需要的时间。
如果 Serenade 无法在不出站换乘的情况下回家,请输出-1。
样例数据
input1
2 1
1 2
1 1 2 2
output1
5
input2
6 9
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
1 1 4 6
output2
27
input3
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
output3
26
数据规模与约定
对于 30%的数据,n≤50,m≤1000n≤50,m≤1000;
对于 60%的数据,n≤500,m≤2000n≤500,m≤2000;
对于 100%的数据,n≤20000,m≤100000n≤20000,m≤100000;
题解
因为公交车有两种走法,上下走和左右走,所以分别建图(只需要管可以换乘的点以及起点和终点),然后换乘点上下图再连线,距离是1,起点和终点的上下图连线是0.
然后用SPFA跑一遍最短路就可以了。具体注释看代码。
代码
代码借鉴了某位大佬,因为我还没怎么搞懂vector的用法
#include<bits/stdc++.h>
#define ll long long
#define memset(x) memset(x, 0, sizeof(x))
using namespace std;
vector< pair<int,int> >E[300005];//从今天开始学着用vector
void add(int from,int to,int val){
E[from].push_back(make_pair(to,val));//在数组的最后添加一个数据
E[to].push_back(make_pair(from,val));//表示from到to的距离是val,双向建
//需要pair做参数的位置,可以直接调用make_pair生成pair对象。
}
struct psx {int x,y,id;}sta[300005];
bool cmp1(psx a,psx b){
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
bool cmp2(psx a,psx b){
if(a.y == b.y) return a.x < b.x;
return a.y < b.y;
}
int n,m;
queue<int> q;
int dis[300005];
bool vis[300005];//是否在队列中
void spfa(){//模板
for(int i = 1; i <= 2*m+4; i++)
dis[i] = 201908230;
dis[m+1] = 0;
vis[m+1] = 1;
q.push(m+1);
while(!q.empty()){
int now = q.front();
q.pop(); vis[now] = 0;
for(int i = 0; i < E[now].size(); i++) {
int to = E[now][i].first;
int val = E[now][i].second;
if( dis[to] > dis[now]+val) {
dis[to] = dis[now]+val;
if(!vis[to]) { vis[to]=1; q.push(to);}
}
}
}
}
int main()
{
freopen("gohome.in","r",stdin);
freopen("gohome.out","w",stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= m+2; i++){
scanf("%d%d", &sta[i].x, &sta[i].y);
sta[i].id=i;//i记录转站点的序号
//m+1是起点,m+2是终点
}
sort(sta+1, sta+m+3, cmp1);//按照x建
for(int i = 1; i < m+2;i++)
if(sta[i].x == sta[i+1].x)
add(sta[i].id, sta[i+1].id, 2*(sta[i+1].y-sta[i].y));
//建立上层图左右结构
sort(sta+1, sta+m+3, cmp2);//按照y建
for(int i = 1; i < m+2; i++)
if(sta[i].y == sta[i+1].y)
add(sta[i].id+m+2, sta[i+1].id+m+2, 2*(sta[i+1].x-sta[i].x));
//建立下层图上下结构
for(int i = 1; i <= m; i++)
add(i, i+m+2, 1);
//上下图之间建立1的距离,转站的花费
add(m+1, m*2+3, 0);//起点的上下图距离为0
add(m+2, m*2+4, 0);//终点的上下图距离为0
spfa();//求单点距离,起点到其他点
if(dis[m+2] == 201908230){
puts("-1");
return 0;
}
printf("%d\n", dis[m+2]);
}