题目传送门:【BZOJ 4152】
题目大意:给定平面上的 n 个点,定义 ( x1 , y1 ) 到 ( x2 , y2 ) 的距离为 min ( | x1 - x2 | , | y1 - y2 | ),求从 1 号点走到 n 号点的最小距离。(原题为费用,不过在这里是等效的)
(2 ≤ n ≤ 2*10
5
,0 ≤
∣x∣
,
∣y∣
≤ 10
9
)
题目分析:
一道考察对题目理解的最短路的好题。
首先,根据题意,这道题肯定与最短路有关。不过我们该怎么去经过最短路的边呢?
容易看到这里题目对两点间的距离作出了定义:两点间距离为它们的 X 轴坐标值之差和 Y 轴坐标值之差的最小值。因此我们可以根据题意,令上述的最小值为两点之间的边长,然后对任意两点建边。
不过总共有 20 万个点,对任意两点建边显然是不可能的。注意到绝大部分的边都是不用建的。其实,我们只需要建立对最短路可能有贡献的边;根据题意,边长为 min ( | x1 - x2 | , | y1 - y2 | ),那么我们对每个点进行两次排序:
先对所有点的 X 坐标排序,然后对相邻的两个点连边(想一想,为什么);然后对所有点的 Y 坐标排序,再对相邻两点建边。(这里可以进行优化,但是为了理解和写起来方便,这样其实已经够了)
建好边之后,跑一遍最短路便可求出 1 号点到 n 号点的最小距离。
本题据说会卡 SPFA!
下面附上 Dijkstra 的代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int MX = 200005;
const int INF = 0x3f3f3f3f;
struct Edge{ //之后建立的边
int next,to,len;
};
Edge edge[4 * MX];
struct Map{ //输入的坐标
int x,y,cnt;
};
Map map[MX];
struct Heapnode{
int d,u;
bool operator < (const Heapnode& r) const {
return d > r.d;
}
};
int n,now = 0,head[MX],dis[MX];
bool vis[MX] = {0};
bool comp_x(Map i,Map j){return i.x < j.x;}
bool comp_y(Map i,Map j){return i.y < j.y;}
void adde(int u,int v,int l){
edge[++now].to = v;
edge[now].len = l;
edge[now].next = head[u];
head[u] = now;
}
void dijkstra(int s){
priority_queue<Heapnode> q;
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;
q.push((Heapnode) {0,s});
while (!q.empty()){
int u = q.top().u;
q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head[u];i;i = edge[i].next){
int v = edge[i].to;
if (dis[u] + edge[i].len < dis[v]){
dis[v] = dis[u] + edge[i].len;
q.push((Heapnode) {dis[v],v});
}
}
}
}
int main(){
cin>>n;
for (int i = 1;i <= n;i++){
cin>>map[i].x>>map[i].y;
map[i].cnt = i;
}
sort(map+1,map+n+1,comp_x);
for (int i = 2;i <= n;i++){
if (map[i].x - map[i-1].x <= abs(map[i].y - map[i-1].y)){
adde(map[i-1].cnt , map[i].cnt , map[i].x-map[i-1].x);
adde(map[i].cnt , map[i-1].cnt , map[i].x-map[i-1].x);
}
}
sort(map+1,map+n+1,comp_y);
for (int i = 2;i <= n;i++){
if (map[i].y - map[i-1].y <= abs(map[i].x - map[i-1].x)){
adde(map[i-1].cnt , map[i].cnt , map[i].y - map[i-1].y);
adde(map[i].cnt , map[i-1].cnt , map[i].y - map[i-1].y);
}
}
dijkstra(1);
cout<<dis[n]<<endl;
return 0;
}