【bzoj4152】[AMPPZ2014]The Captain 堆优化Dijkstra
题目描述
给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。
输入
第一行包含一个正整数n(2<=n<=200000),表示点数。
接下来n行,每行包含两个整数x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每个点的坐标。
输出
一个整数,即最小费用。
样例输入
5
2 2
1 1
4 5
7 1
6 7
样例输出
2
题解
最短路神题
这种题貌似不需要放思考过程?
发现$|x_1-x_2|$类型的边只有横坐标相邻的点之间有必要连,其余的都可以由这些边表示,因此按横坐标排序,相邻的点连边。纵坐标同理。
然后直接跑堆优化Dijkstra即可。
时间复杂度$O(n\log n)$
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> #define N 200010 using namespace std; typedef pair<int , int> pr; struct data { int x , y , id; }a[N]; priority_queue<pr> q; int head[N] , to[N << 2] , len[N << 2] , next[N << 2] , cnt , dis[N] , vis[N]; bool cmpx(data a , data b) { return a.x < b.x; } bool cmpy(data a , data b) { return a.y < b.y; } inline void add(int x , int y , int z) { to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt; to[++cnt] = x , len[cnt] = z , next[cnt] = head[y] , head[y] = cnt; } int main() { int n , i , x; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].x , &a[i].y) , a[i].id = i; sort(a + 1 , a + n + 1 , cmpx); for(i = 1 ; i < n ; i ++ ) add(a[i].id , a[i + 1].id , a[i + 1].x - a[i].x); sort(a + 1 , a + n + 1 , cmpy); for(i = 1 ; i < n ; i ++ ) add(a[i].id , a[i + 1].id , a[i + 1].y - a[i].y); memset(dis , 0x3f , sizeof(dis)) , dis[1] = 0 , q.push(pr(0 , 1)); while(!q.empty()) { x = q.top().second , q.pop(); if(vis[x]) continue; vis[x] = 1; for(i = head[x] ; i ; i = next[i]) if(dis[to[i]] > dis[x] + len[i]) dis[to[i]] = dis[x] + len[i] , q.push(pr(-dis[to[i]] , to[i])); } printf("%d\n" , dis[n]); return 0; }