图论---The Captain
B-The Captain
给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。
Input
第一行包含一个正整数n(2<=n<=200000),表示点数。
接下来n行,每行包含两个整数x[i],yi,依次表示每个点的坐标。
Output
一个整数,即最小费用。
Sample Input
5
2 2
1 1
4 5
7 1
6 7
Sample Output
2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 200010
#define inf 0x3f3f3f3f
#define pa pair<long long, int>
using namespace std;
int head[N];
long long dis[N];
int n, num;
bool vis[N];
struct node
{
int x, y, z;
}a[N];
priority_queue<pa, vector<pa>, greater<pa> > q;
bool cmp_x(node x,node y)
{
return x.x < y.x;
}
bool cmp_y(node x,node y)
{
return x.y < y.y;
}
struct edge
{
int u, v, next;
long long w;
edge(){next=-1;}
}ed[4*N];
void build(int u,int v,int w)
{
num++;
ed[num].w=w;
ed[num].v=v;
ed[num].next=head[u];
head[u]=num;
}
void SPFA()
{
memset(vis, 0, sizeof(vis));
for(int i=1; i<=n; i++) dis[i]=inf;
dis[1]=0;
q.push(make_pair(0, 1));
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u]; i!=-1; i=ed[i].next)
{
int v=ed[i].v;
if(dis[v]>dis[u]+ed[i].w)
{
dis[v]=dis[u]+ed[i].w;
q.push(make_pair(dis[v], v));
}
}
}
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d", &n);
for (int i=1; i<=n; i++)
{
scanf("%d%d", &a[i].x, &a[i].y);
a[i].z=i;
}
sort(a+1, a+n+1, cmp_x);
for(int i=1; i<n; i++)
{
build(a[i].z, a[i+1].z, a[i+1].x-a[i].x),
build(a[i+1].z, a[i].z, a[i+1].x-a[i].x);
}
sort(a+1, a+n+1, cmp_y);
for(int i=1; i<n; i++)
{
build(a[i].z, a[i+1].z, a[i+1].y-a[i].y),
build(a[i+1].z, a[i].z, a[i+1].y-a[i].y);
}
SPFA();
printf("%lld\n", dis[n]);
return 0;
}
- 我们不难发现,如果有一个点P在M,N两个点之间,从M到N得代价一定大于从P到M再从P到N得代价。
- 换言之,我们的边应该建在横纵坐标相邻的点之间。
- 为此目的,我们把点们按照横坐标从小到大排序,再把点们按照纵坐标从小到大排序。然后直接按排好的顺序两辆排序。
- 要用Dijkstra的话。。。除非你开堆优化的Dijkstra,否则是过不了的。