题意
2046 年 OI 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由2n2n2n条地铁线路构成,组成了一个nnn纵nnn横的交通网。如下图所示,这2n2n2n条线路每条线路都包含nnn个车站,而每个车站都在一组纵横线路的交汇处。
出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有mmm个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行 1 站需要 2 分钟,而站内换乘需要步行 1 分钟。Serenade 想要知道,在不中途出站的前提下,他从学校回家最快需要多少时间(等车时间忽略不计)
题解
分层图最短路。
直接建立矩阵是不行的,
n2
n
2
太大了。所以要考虑建图方式。
以为能够转向只能在中转站,考虑到如果起点和终点所在的行和列上,如果没有中转站,是不可能从起点出发或者到达终点的。所以我们只需要对中转站进行建图。对每个中转站行和列上的中转站连边,边权为花费的时间,也就是2倍的曼哈顿距离。
然后起点和行列上的中转站连边,终点和行列上的中转站连边,分层图最短路即可。
分层图的时候,只需要记录到达中转站/终点/起点的最短时间即可,分别考虑换乘(改变方向)和不换乘的情况。
代码
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull MOD = 1610612741;
int head[nmax], tot;
int sx, sy, ex ,ey;
struct edge {
int to, nxt, w;
}e[nmax << 1];
void add_edge(int u, int v, int w) {
e[tot].to = v;
e[tot].nxt = head[u];
e[tot].w = w;
head[u] = tot++;
// printf("debug add %d %d %d \n", u, v, w);
}
struct nope {
int x, y ,id;
}p[nmax];
bool cmp1(nope a, nope b) {
if(a.x == b.x)
return a.y < b.y;
else
return a.x < b.x;
}
bool cmp2(nope a, nope b) {
if(a.y == b.y)
return a.x < b.x;
else
return a.y < b.y;
}
bool cmp3(nope a, nope b) {
return a.id < b.id;
}
inline int getdist(nope a, nope b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
int getway(nope a, nope b) {
if(a.x == b.x)
return 0;
else if(a.y == b.y)
return 1;
}
int n, m;
int dist[nmax];
bool visit[nmax];
struct node {
int index;
int dist;
int way;
bool operator < (const node & rhs) const {
return dist > rhs.dist;
}
};
priority_queue<node> pq;
int bfs(nope st, nope ed) {
for(int i = 0; i <= m +1; ++i) {
// dist[i][0] = dist[i][1] = INF;
// visit[i][0] = visit[i][1] = false;
dist[i] = INF;
visit[i] = false;
}
while(!pq.empty()) pq.pop();
for(int i = head[st.id]; i != -1; i = e[i].nxt) {
int v = e[i].to;
int w = e[i].w;
if(getway(p[st.id], p[v]) == 0) {
dist[v] = w;
pq.push(node{v, w, 0});
} else {
dist[v] = w;
pq.push(node{v, w, 1});
}
}
dist[st.id] = 0;
// visit[st.id] = true;
// pq.pop(nope{st.id, 0, 0});
// pq.pop(nope{st.id, 0, 1});
while(!pq.empty()) {
node tmp = pq.top();
pq.pop();
int u = tmp.index;
int way = tmp.way;
if(visit[u])
continue;
visit[u] = true;
if(u == ed.id)
return tmp.dist;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
int w = e[i].w;
if(!visit[v]) {
int thisway = getway(p[u], p[v]);
if(thisway != way && dist[v] > dist[u] + 1 + w) {
dist[v] = dist[u] + 1 + w;
pq.push(node{v, dist[v], thisway});
} else if(thisway == way && dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push(node{v, dist[v], thisway});
}
}
}
}
return INF;
}
int main(){
scanf("%d %d", &n, &m);
memset(head, -1, sizeof head);
for(int i = 1; i <= m; ++i) {
scanf("%d %d", &p[i].x, &p[i].y);
p[i].id = i;
}
scanf("%d %d %d %d", &sx, &sy, &ex, &ey);
nope ss = nope{sx, sy, 0};
nope ee = nope{ex, ey, m + 1};
if(sx == ex || sy == ey) {
printf("%d\n", 2 * getdist(ss, ee));
} else {
bool shave = false, ehave = false;
p[0] = ss;
p[m+1] = ee;
sort(p + 1, p + m + 1, cmp1);
for(int i = 1; i <= m - 1; ++i) {
if(p[i].x == p[i + 1].x) {
int w = 2 * getdist(p[i], p[i+1]);
add_edge(p[i].id, p[i+1].id, w);
add_edge(p[i+1].id, p[i].id, w);
}
}
sort(p + 1, p + 1 + m, cmp2);
for(int i = 1; i <= m; ++i) {
if(p[i].y == p[i+1].y) {
int w = 2 * getdist(p[i], p[i+1]);
add_edge(p[i].id, p[i+1].id, w);
add_edge(p[i+1].id, p[i].id, w);
}
if(p[i].x == sx || p[i].y == sy) {
add_edge(ss.id, p[i].id, 2 * getdist(p[i], ss));
add_edge(p[i].id, ss.id, 2 * getdist(p[i], ss));
}
if(p[i].x == ex || p[i].y == ey) {
add_edge(ee.id, p[i].id, 2 * getdist(p[i], ee));
add_edge(p[i].id, ee.id, 2 * getdist(p[i], ee));
}
}
sort(p + 1, p + 1 + m, cmp3);
int ans = bfs(ss, ee);
if(ans == INF)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}