【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

题解:做法很神,也很简洁。

将所有点按x排序,显然只需要在相邻的点之间连边即可,然后在按y排序做一遍,跑最短路就完事了。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <utility>
#define mp(A,B) make_pair(A,B)
using namespace std;
const int maxn=200010;
typedef long long ll;
struct node
{
	int x,y,org;
}p[maxn];
int n,cnt;
int to[maxn<<2],next[maxn<<2],head[maxn],val[maxn<<2];
bool vis[maxn];
ll dis[maxn];
priority_queue<pair<ll,int> > q;
inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=nc();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=nc();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=nc();
	return ret*f;
}
bool cmpx(const node &a,const node &b)
{
	return a.x<b.x;
}
bool cmpy(const node &a,const node &b)
{
	return a.y<b.y;
}
inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=c,next[cnt]=head[b],head[b]=cnt++;
}
int main()
{
	n=rd();
	register int i,u;
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd(),p[i].org=i;
	sort(p+1,p+n+1,cmpx);
	for(i=1;i<n;i++)	add(p[i].org,p[i+1].org,p[i+1].x-p[i].x);
	sort(p+1,p+n+1,cmpy);
	for(i=1;i<n;i++)	add(p[i].org,p[i+1].org,p[i+1].y-p[i].y);
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0,q.push(mp(0,1));
	while(!q.empty())
	{
		u=q.top().second,q.pop();
		if(vis[u])	continue;
		if(u==n)
		{
			printf("%lld\n",dis[n]);
			return 0;
		}
		vis[u]=1;
		for(i=head[u];i!=-1;i=next[i])	if(dis[to[i]]>dis[u]+val[i])
			dis[to[i]]=dis[u]+val[i],q.push(mp(-dis[to[i]],to[i]));
	}
}

 

posted @ 2017-10-15 11:35  CQzhangyu  阅读(340)  评论(0编辑  收藏  举报