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
2 2
1 1
4 5
7 1
6 7
Sample Output
2
按题意i号点到j号点的距离是min(|xi-xj|,|yi-yj|),我们可以将其转化成两条边,一条权值为|xi-xj|,一条权值为|yi-yj|,这显然是没问题的。
那么问题就转化成一维问题,如何连最少的边,我们发现按维排序每次将相邻的点连边即可。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=200010; const int maxm=800010; const int inf=1e9; struct Dijkstra { int n,m,d[maxn],done[maxn],first[maxn],next[maxm]; struct Edge {int from,to,dist;}edges[maxm]; struct HeapNode { int u,d; bool operator < (const HeapNode& ths) const {return d>ths.d;} }; void init(int n) { this->n=n;m=1; } void AddEdge(int u,int v,int w) { edges[m]=(Edge){u,v,w};next[m]=first[u];first[u]=m++; } priority_queue<HeapNode> Q; void solve(int s) { rep(i,1,n) d[i]=inf; d[s]=0;Q.push((HeapNode){s,0}); while(!Q.empty()) { int x=Q.top().u;Q.pop(); if(done[x]) continue;done[x]=1; ren { Edge& e=edges[i]; if(d[e.to]>d[x]+e.dist) { d[e.to]=d[x]+e.dist; Q.push((HeapNode){e.to,d[e.to]}); } } } } }sol; struct Point { int x,y,id; }A[maxn]; bool cmp1(Point a,Point b) {return a.x<b.x;} bool cmp2(Point a,Point b) {return a.y<b.y;} int main() { int n=read();sol.init(n); rep(i,1,n) A[A[i].id=i].x=read(),A[i].y=read(); sort(A+1,A+n+1,cmp1); rep(i,1,n) { if(i!=1) sol.AddEdge(A[i].id,A[i-1].id,A[i].x-A[i-1].x); if(i!=n) sol.AddEdge(A[i].id,A[i+1].id,A[i+1].x-A[i].x); } sort(A+1,A+n+1,cmp2); rep(i,1,n) { if(i!=1) sol.AddEdge(A[i].id,A[i-1].id,A[i].y-A[i-1].y); if(i!=n) sol.AddEdge(A[i].id,A[i+1].id,A[i+1].y-A[i].y); } sol.solve(1);printf("%d\n",sol.d[n]); return 0; }