BZOJ4152: [AMPPZ2014]The Captain

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

题解Here!
这题显然直接$SPFA$对吧。。。
但是那个建图怎么搞?
$O(n^2)\text{的Force?}\tan(\frac{\pi}{2}+k\pi),k\in Z$。。。
我们不难发现这样一个事实:
如果有一个点$P$在$M,N$两个点之间,从$M$到$N$得代价一定大于从$M$到$P$,再从$P$到$N$得代价。
换言之,我们的边应该建在横纵坐标相邻的点之间。 
这就是一个贪心啊。。。
为此目的,我们把点们按照横坐标从小到大排序,再把点们按照纵坐标从小到大排序。
然后直接按排好的顺序在相邻两个节点之间建双向边。
然后直接$SPFA$即可。
然而,出题人很不友好。。。
这题卡$SPFA$!这题卡$SPFA+SLF$!!这题卡$SPFA+SLF+LLL$!!!重要的事情说三遍!!!
害得我只能写堆优化$Dijkstra$。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 200010
#define MAX (1LL<<61)
using namespace std;
int n,s,t,c=1;
int head[MAXN];
long long path[MAXN];
bool vis[MAXN];
struct Point{
	int x,y,id;
}point[MAXN];
struct Edge{
	int next,to;
	long long w;
}a[MAXN<<2];
struct node{
    int x,dis;
    bool operator <(const node &p)const{
        return dis>p.dis;
    }
};
priority_queue<node> q;
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline bool cmp1(const Point &p,const Point &q){
	return p.x<q.x;
}
inline bool cmp2(const Point &p,const Point &q){
	return p.y<q.y;
}
inline int relax(int u,int v,long long w){
	if(path[v]>path[u]+w){
		path[v]=path[u]+w;
		return 1;
	}
	return 0;
}
inline void add(int u,int v,int w){
	a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
	a[c].to=u;a[c].w=w;a[c].next=head[v];head[v]=c++;
}
void dijkstra(){
    node u,v;
    for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
    u.x=s;u.dis=path[s]=0;
    q.push(u);
    while(!q.empty()){
        u=q.top();
        q.pop();
        if(!vis[u.x]){
            vis[u.x]=true;
            for(int i=head[u.x];i;i=a[i].next){
                v.x=a[i].to;
                if(!vis[v.x]){
                    path[v.x]=min(path[v.x],path[u.x]+a[i].w);
                    v.dis=u.dis+a[i].w;
                    q.push(v);
                }
            }
        }
    }
}
void work(){
	dijkstra();
	printf("%lld\n",path[t]);
}
void init(){
	n=read();
	s=1;t=n;
	for(int i=1;i<=n;i++){
		point[i].x=read();point[i].y=read();
		point[i].id=i;
	}
	sort(point+1,point+n+1,cmp1);
	for(int i=1;i<n;i++)add(point[i].id,point[i+1].id,point[i+1].x-point[i].x);
	sort(point+1,point+n+1,cmp2);
	for(int i=1;i<n;i++)add(point[i].id,point[i+1].id,point[i+1].y-point[i].y);
}
int main(){
	init();
	work();
    return 0;
}

 

posted @ 2018-08-29 18:46  符拉迪沃斯托克  阅读(300)  评论(0编辑  收藏  举报
Live2D