【bzoj4152】[AMPPZ2014]The Captain 堆优化Dijkstra

时间:2021-07-09 22:09:15

题目描述

给定平面上的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;
}