图论---The Captain

B-The Captain

给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。

Input

第一行包含一个正整数n(2<=n<=200000),表示点数。
接下来n行,每行包含两个整数x[i],yi,依次表示每个点的坐标。

Output

一个整数,即最小费用。

Sample Input

5
2 2
1 1
4 5
7 1
6 7

Sample Output

2
#include<cstdio>  
#include<cstring>    
#include<algorithm>  
#include<queue> 
#define N 200010
#define inf 0x3f3f3f3f
#define pa pair<long long, int>
using namespace std;
int head[N];
long long dis[N];
int n, num;
bool vis[N];
struct node
{  
    int x, y, z;
}a[N];
priority_queue<pa, vector<pa>, greater<pa> > q;
bool cmp_x(node x,node y)
{
	return x.x < y.x;
}
bool cmp_y(node x,node y)
{
	return x.y < y.y;
}
struct edge
{
    int u, v, next;
    long long w;
    edge(){next=-1;}
}ed[4*N];
void build(int u,int v,int w)
{  
    num++;
    ed[num].w=w;
    ed[num].v=v;
    ed[num].next=head[u];
    head[u]=num;
}
void SPFA()
{
    memset(vis, 0, sizeof(vis));
    for(int i=1; i<=n; i++) dis[i]=inf;
    dis[1]=0;
    q.push(make_pair(0, 1));
    while(!q.empty())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head[u]; i!=-1; i=ed[i].next)
        {
            int v=ed[i].v;
            if(dis[v]>dis[u]+ed[i].w)
            {
                dis[v]=dis[u]+ed[i].w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
}
int main()  
{  
    memset(head, -1, sizeof(head));
    scanf("%d", &n);  
    for (int i=1; i<=n; i++)  
    {  
        scanf("%d%d", &a[i].x, &a[i].y);  
        a[i].z=i;  
    }  
    sort(a+1, a+n+1, cmp_x);  
    for(int i=1; i<n; i++)
    {
        build(a[i].z, a[i+1].z, a[i+1].x-a[i].x),
        build(a[i+1].z, a[i].z, a[i+1].x-a[i].x);   
    } 
    sort(a+1, a+n+1, cmp_y);  
    for(int i=1; i<n; i++) 
    {
        build(a[i].z, a[i+1].z, a[i+1].y-a[i].y),
        build(a[i+1].z, a[i].z, a[i+1].y-a[i].y);   
    }
    SPFA();  
    printf("%lld\n", dis[n]);  
    return 0;  
}
  • 我们不难发现,如果有一个点P在M,N两个点之间,从M到N得代价一定大于从P到M再从P到N得代价。
  • 换言之,我们的边应该建在横纵坐标相邻的点之间。
  • 为此目的,我们把点们按照横坐标从小到大排序,再把点们按照纵坐标从小到大排序。然后直接按排好的顺序两辆排序。
  • 要用Dijkstra的话。。。除非你开堆优化的Dijkstra,否则是过不了的。
posted @ 2020-02-17 11:31  orange_lyc  阅读(96)  评论(0编辑  收藏  举报