给定一个 n ∗ n n*n n∗n的网格,在这个网格中给出两个坐标,分别作为起点和终点。并且在图中存在 m m m个传送阵,传送阵的坐标已知。从起点开始向终点走,相邻两个位置之间花费一个单位,如果走到与某个传送阵同行或者同列,那么可以不耗花费的传送到那个传送阵的位置。问从起点到终点,最少花费多少单位。
1 ≤ n ≤ 1 0 9 1 \leq n \leq 10^9 1≤n≤109
0 ≤ m ≤ 1 0 5 0 \leq m \leq 10^5 0≤m≤105
如果传送阵直接建一个完全图,那么显然会爆空间和时间,因此需要考虑更简洁的建图方式。
首先我们可以考虑到,两个传送阵之间的距离为 m i n ( x 2 − x 1 , y 2 − y 1 ) min(x_2 - x_1, y_2 - y_1) min(x2−x1,y2−y1),这就等价于两个传送阵在同一行或者同一列上。因此,我们可以对传送阵的横坐标排序,相邻两个连起来;再对传送阵的纵坐标排序,相邻两个连起来。因为要求的是最短路,所以两点之间出现重边也没关系。
最后,将起点作为 0 0 0号点,终点作为 m + 1 m+1 m+1号点,起点向每一个传送阵连一条边,终点向每个传送阵连一条边,起点和终点之间再连一条边。值得注意的是,起点到传送阵的距离计算方式和传送阵到终点的距离计算方式是不同的,因为一个可以传送,另一个不能传送。
这样图就建好了,然后跑一个Dijkstra算法就完成了。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
typedef pair<int,ll> pil;
const int N = 100010, M = 10 * N;
const ll inf = 1e18;
int sz,n,S,T;
int h[N], e[M], ne[M], idx;
ll w[M];
ll xx[N], yy[N];
ll dist[N];
bool st[N];
pli x_id[N], y_id[N];
void add(int a,int b,ll c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void dijkstra()
{
for(int i=0;i<=n+1;i++) dist[i] = inf;
memset(st,0,sizeof(st));
dist[0] = 0;
priority_queue<pli,vector<pli>,greater<pli> > heap;
heap.push({
dist[0],0});
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second;
ll distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i=h[ver];~i;i=ne[i]){
int j = e[i];
if(dist[j]>distance+w[i]){
dist[j] = distance + w[i];
heap.push({
dist[j],j});
}
}
}
}
int main()
{
cin >> sz >> n;
memset(h,-1,sizeof(h));
ll sx,sy,fx,fy;
cin >> sx >> sy >> fx >> fy;
ll dd = abs(sx - fx) + abs(sy - fy);
add(0,n+1,dd), add(n+1,0,dd);
for(int i=1;i<=n;i++){
cin >> xx[i] >> yy[i];
x_id[i] = {
xx[i],i}, y_id[i] = {
yy[i],i};
}
for(int i=1;i<=n;i++){
ll d = min(abs(sx-xx[i]),abs(sy-yy[i]));
add(0,i,d), add(i,0,d);
}
for(int i=1;i<=n;i++){
ll d = abs(fx-xx[i]) + abs(fy-yy[i]);
add(n+1,i,d), add(i,n+1,d);
}
sort(x_id+1,x_id+n+1);
sort(y_id+1,y_id+n+1);
for(int i=1;i<n;i++){
int id1 = x_id[i].second, id2 = x_id[i+1].second;
ll d = abs(x_id[i].first - x_id[i+1].first);
add(id1,id2,d), add(id2,id1,d);
}
for(int i=1;i<n;i++){
int id1 = y_id[i].second, id2 = y_id[i+1].second;
ll d = abs(y_id[i].first - y_id[i+1].first);
add(id1,id2,d), add(id2,id1,d);
}
dijkstra();
cout << dist[n+1] << endl;
return 0;
}