BZOJ 4152: [AMPPZ2014]The Captain(最短路)

自為風月馬前卒發表於2018-02-26
Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 1550  Solved: 619
[Submit][Status][Discuss]

Description

給定平面上的n個點,定義(x1,y1)到(x2,y2)的費用為min(|x1-x2|,|y1-y2|),求從1號點走到n號點的最小費用。

 

Input

第一行包含一個正整數n(2<=n<=200000),表示點數。
接下來n行,每行包含兩個整數x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每個點的座標。
 
 

 

Output

一個整數,即最小費用。

 

Sample Input

5
2 2
1 1
4 5
7 1
6 7

Sample Output

2

HINT

 

Source

鳴謝Claris上傳

 

很有意思的一道題目

兩個點之間的費用為min(|x1-x2|,|y1-y2|),就相當於對於x和y分別連邊。

對於1,2,3這三個點,若x1<=x2<=x3,不難發現|x1-x3|這條邊沒有必要連。

那麼我們把所有點按x排序,每個點向相鄰點連權值為x差的絕對值的邊。

再把所有點按y排序,同理。

然後直接跑最短路即可。

記得開long long

 

 

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define Pair pair<int,int>
#define F first
#define S second
#define int long long 
const int MAXN=1e6+10;
using namespace std;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int N;
struct node
{
    int id,x,y;
}Point[MAXN];
int comp(const node &a,const node &b){return a.x<b.x;}
int comp2(const node &a,const node &b){return a.y<b.y;}
int dis[MAXN],vis[MAXN];
struct E
{
    int u,v,w,nxt;
}edge[MAXN];
int head[MAXN],num=1;
inline void AddEdge(int x,int y,int z)
{
    edge[num].u=x;edge[num].v=y;edge[num].w=z;edge[num].nxt=head[x];
    head[x]=num++;
}
void Dijstra()
{
    memset(dis,0xf,sizeof(dis));dis[1]=0;
    priority_queue<Pair>q;
    q.push(make_pair(0,1));
    while(q.size()!=0)
    {
        while(vis[q.top().S]&&q.size()>0) q.pop();
        Pair p=q.top();
        vis[p.S]=1;
        for(int i=head[p.S];i!=-1;i=edge[i].nxt)
            if(dis[edge[i].v]>dis[p.S]+edge[i].w)
                dis[edge[i].v]=dis[p.S]+edge[i].w,
                q.push(make_pair(-dis[edge[i].v],edge[i].v));
    }
    printf("%lld",dis[N]);
}
main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    memset(head,-1,sizeof(head));
    N=read();
    for(int i=1;i<=N;i++) 
        Point[i].id=i,Point[i].x=read(),Point[i].y=read();
    sort(Point+1,Point+N+1,comp);
    for(int i=1;i<=N-1;i++)
        AddEdge(Point[i].id,Point[i+1].id,Point[i+1].x-Point[i].x),
        AddEdge(Point[i+1].id,Point[i].id,Point[i+1].x-Point[i].x);
    sort(Point+1,Point+N+1,comp2);
    for(int i=1;i<=N-1;i++) 
        AddEdge(Point[i].id,Point[i+1].id,Point[i+1].y-Point[i].y),
        AddEdge(Point[i+1].id,Point[i].id,Point[i+1].y-Point[i].y);
    Dijstra();
    return 0;
}