传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4152
Description
给定平面上的个点,定义到的费用为,求从1号点走到n号点的最小费用。
Input
第一行包含一个正整数,表示点数。
接下来行,每行包含两个整数,依次表示每个点的坐标。
Output
一个整数,即最小费用。
Sample Input
5
2 2
1 1
4 5
7 1
6 7
Sample Output
2
如果暴力建图,连条边,是会爆内存与时间的。
我们容易发现一个性质:我们先忽略掉坐标的其中一维,比如只考虑横坐标时,把点按横坐标排好序后,的边等价于的边,因为的边权为,而的总边权为,故为等价的,故我们只需要以一条链串过去,就可以表示所有的边,同时减少多余的边了;
所以我们以为关键字先排一遍序,相邻点之间建一条边权为横坐标之差的边;再以为关键字排一遍序,相邻点之间建一条边权为纵坐标之差的边。因为跑最短路算法取的是更小的一条边,所以每两个点之间的两条边(一条以算,一条以算),也能等价于题目上说的,就建好了题目要求的图。
由于较大,需要用用堆优化的或(但是听说会被卡?)
代码:(我是手写堆的铁头娃)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct forward_star
{
int next,to;
long long w;
};
struct coordinate
{
int x,y,label;
};
int n,cnt,tot;
forward_star edge[800001];
int head[200001];
long long dist[200001];
int heap[200001];
int ref[200001];
bool vis[200001];
bool in[200001];
coordinate point[200001];
bool cmp1(coordinate i,coordinate j)
{
return (i.x<j.x);
}
bool cmp2(coordinate i,coordinate j)
{
return (i.y<j.y);
}
void add(int u,int v,int w)
{
cnt++;
edge[cnt].to=v;
edge[cnt].next=head[u];
edge[cnt].w=w;
head[u]=cnt;
}
void up(int now)
{
while (now>1&&dist[heap[now]]<dist[heap[now/2]])
{
swap(heap[now],heap[now/2]);
swap(ref[heap[now]],ref[heap[now/2]]);
now/=2;
}
}
void down(int now)
{
while (now*2<=tot)
{
if (now*2+1<=tot)
{
int k;
if (dist[heap[now*2]]<dist[heap[now*2+1]]) k=now*2; else k=now*2+1;
if (dist[heap[now]]>dist[heap[k]])
{
swap(heap[now],heap[k]);
swap(ref[heap[now]],ref[heap[k]]);
now=k;
}
else break;
}
else
{
if (dist[heap[now]]>dist[heap[now*2]])
{
swap(heap[now],heap[now*2]);
swap(ref[heap[now]],ref[heap[now*2]]);
now*=2;
}
else break;
}
}
}
void adjust()
{
heap[1]=heap[tot];
ref[heap[1]]=1;
tot--;
down(1);
}
void addheap(int i)
{
heap[++tot]=i;
ref[i]=tot;
up(tot);
}
void dijkstra()
{
for (int i=1;i<=n;i++)
dist[i]=1000000000000000000ll;
dist[1]=0;
in[1]=true;
addheap(1);
while (tot>0)
{
int now=heap[1];
adjust();
vis[now]=true;
int j=head[now];
while (j!=0)
{
if (dist[now]+edge[j].w<dist[edge[j].to])
{
dist[edge[j].to]=dist[now]+edge[j].w;
if (!in[edge[j].to])
{
in[edge[j].to]=true;
addheap(edge[j].to);
} else if (!vis[edge[j].to]) up(ref[edge[j].to]);
}
j=edge[j].next;
}
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
point[i].label=i;
}
sort(point+1,point+n+1,cmp1);
for (int i=1;i<n;i++)
{
add(point[i].label,point[i+1].label,point[i+1].x-point[i].x);
add(point[i+1].label,point[i].label,point[i+1].x-point[i].x);
}
sort(point+1,point+n+1,cmp2);
for (int i=1;i<n;i++)
{
add(point[i].label,point[i+1].label,point[i+1].y-point[i].y);
add(point[i+1].label,point[i].label,point[i+1].y-point[i].y);
}
dijkstra();
printf("%lld",dist[n]);
}