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
对于这道题,由于所以对于任意一个点,只需要将它与和它横坐标或纵坐标相邻的点连边,然后跑一遍最短路即可,下面是程序:
dijkstra+堆优化:
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int N=200005;
struct node{
int x;
ll w;
bool operator <(const node &p)const{
return w>p.w;
}
};
struct Point{
int x,y,i;
}a[N];
struct edge{
int v,next;
ll w;
}e[N<<2];
ll dis[N];
int head[N],k;
bool vis[N];
priority_queue<node>q;
bool cmp1(Point a,Point b){
return a.x<b.x;
}
bool cmp2(Point a,Point b){
return a.y<b.y;
}
void add(int u,int v,ll w){
e[++k]=(edge){v,head[u],w};
head[u]=k;
}
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1]=0;
q.push((node){1,0});
int i,x;
while(!q.empty()){
x=q.top().x;
q.pop();
if(vis[x]){
continue;
}
vis[x]=1;
for(i=head[x];i!=-1;i=e[i].next){
if(dis[x]+e[i].w<dis[e[i].v]){
dis[e[i].v]=dis[x]+e[i].w;
q.push((node){e[i].v,dis[e[i].v]});
}
}
}
}
int main(){
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].i=i;
}
memset(head,-1,sizeof(head));
sort(a+1,a+n+1,cmp1);
for(i=1;i<n;i++){
add(a[i].i,a[i+1].i,a[i+1].x-a[i].x);
add(a[i+1].i,a[i].i,a[i+1].x-a[i].x);
}
sort(a+1,a+n+1,cmp2);
for(i=1;i<n;i++){
add(a[i].i,a[i+1].i,a[i+1].y-a[i].y);
add(a[i+1].i,a[i].i,a[i+1].y-a[i].y);
}
dijkstra();
printf("%lld\n",dis[n]);
return 0;
}
SPFA(这题卡SPFA,但加上SLF和网上的玄妙优化(入队多的放队首)可以卡过):
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int N=200005;
ll dis[N];
int sum[N];
struct queue{
int l,r,a[N];
void clear(){
l=0,r=1;
}
bool empty(){
return l+1==r;
}
void push(int x){
if(dis[x]<dis[a[(l+1)%N]]||sum[x]>sum[a[(l+1)%N]]){
a[l]=x;
l=(l+N-1)%N;
}
else{
a[r]=x;
r=(r+1)%N;
}
++sum[x];
}
void pop(){
l=(l+1)%N;
}
int front(){
return a[(l+1)%N];
}
}q;
struct Point{
int x,y,i;
}a[N];
struct edge{
int v,next;
ll w;
}e[N<<2];
int head[N],k;
bool vis[N];
bool cmp1(Point a,Point b){
return a.x<b.x;
}
bool cmp2(Point a,Point b){
return a.y<b.y;
}
void add(int u,int v,ll w){
e[++k]=(edge){v,head[u],w};
head[u]=k;
}
void SPFA(){
memset(dis,0x3f,sizeof(dis));
q.clear();
dis[1]=0;
q.push(1);
vis[1]=1;
int u,v,i;
while(!q.empty()){
u=q.front();
q.pop();
vis[u]=0;
for(i=head[u];i!=-1;i=e[i].next){
v=e[i].v;
if(dis[u]+e[i].w<dis[v]){
dis[v]=dis[u]+e[i].w;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
}
int main(){
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].i=i;
}
memset(head,-1,sizeof(head));
sort(a+1,a+n+1,cmp1);
for(i=1;i<n;i++){
add(a[i].i,a[i+1].i,a[i+1].x-a[i].x);
add(a[i+1].i,a[i].i,a[i+1].x-a[i].x);
}
sort(a+1,a+n+1,cmp2);
for(i=1;i<n;i++){
add(a[i].i,a[i+1].i,a[i+1].y-a[i].y);
add(a[i+1].i,a[i].i,a[i+1].y-a[i].y);
}
SPFA();
printf("%lld\n",dis[n]);
return 0;
}