【bzoj4152】【AMPPZ2014】【The Captain】【最短路】

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
题解:
把每个点先按横坐标排序,相邻点连边。
再把每个点按纵坐标排序,相邻点连边。
然后跑最短路即可。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 200005
#define zff pair<long long,int>
using  namespace std;
struct use{int x,y,kind;}p[N];
struct use2{int st,en;long long v;}e[N*4];
priority_queue<zff,vector<zff>,greater<zff> >q;
int point[N],next[N*4],cnt,n,x,y;
long long dis[N];
bool f[N];
bool cmp(use a,use b){return a.x<b.x;}
bool cmp2(use a,use b){return a.y<b.y;}
void add(int x,int y,int v){
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].st=x;e[cnt].en=y;e[cnt].v=(long long)v;
}
void spfa()  
{  
    memset(f,0,sizeof(f));  
    memset(dis,127,sizeof(dis));  
    dis[1]=0;q.push(make_pair(0,1));  
    while (!q.empty())  
    {  
        int x=q.top().second;q.pop();  
        if (f[x]) continue;f[x]=1;  
        for (int i=point[x];i;i=next[i])  
          if (dis[e[i].en]>dis[x]+e[i].v)  
          {  
            dis[e[i].en]=dis[x]+e[i].v;  
            q.push(make_pair(dis[e[i].en],e[i].en));  
          }  
    }  
}  
int main(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++){scanf("%d%d",&x,&y);p[i].x=x;p[i].y=y;p[i].kind=i;}
  sort(p+1,p+n+1,cmp);
  for (int i=1;i<n;i++){
    add(p[i].kind,p[i+1].kind,p[i+1].x-p[i].x);
    add(p[i+1].kind,p[i].kind,p[i+1].x-p[i].x);
  } 
  sort(p+1,p+n+1,cmp2);
  for (int i=1;i<n;i++){
    add(p[i].kind,p[i+1].kind,p[i+1].y-p[i].y);
    add(p[i+1].kind,p[i].kind,p[i+1].y-p[i].y);
  }
  spfa();
  cout<<dis[n]<<endl; 
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值