bzoj 3170: [Tjoi 2013]松鼠聚会
3170: [Tjoi 2013]松鼠聚会
Description
有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。
Input
第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5
下面N行,每行给出x,y表示其家的坐标。
-10^9<=x,y<=10^9
Output
表示为了聚会走的路程和最小为多少。
Sample Input
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
Sample Output
20
题解:
直接搞o(n)的算法吧。。
首先这题的距离应该是dis(x,y)=max{|x-y|,|x+y|};
这是切比雪夫距离,可以去网上搜搜它与曼哈顿距离的转化,就是把(x,y)变为((x-y)/2,(x+y)/2)
方便起见,我没有除2,最后输出答案的时候再除就行了。。
然后就是乱搞了,按某个轴排个序,再求每个点到其他点距离的前缀和,后缀和。搞2遍。。
#include<stdio.h> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int N=500005; struct node { ll a,b; int id; }p[N]; int n,i,x,y; ll ans,lx[N],ly[N],rx[N],ry[N]; bool cmpx(const node&x,const node&y) { return x.a<y.a; } bool cmpy(const node&x,const node&y) { return x.b<y.b; } int main() { scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&x,&y); p[i].a=x-y; p[i].b=x+y; p[i].id=i; } sort(p+1,p+n+1,cmpx); for(i=1;i<=n;i++) lx[p[i].id]=lx[p[i-1].id]+(p[i].a-p[i-1].a)*(i-1); for(i=n;i>=1;i--) rx[p[i].id]=rx[p[i+1].id]+(p[i+1].a-p[i].a)*(n-i); sort(p+1,p+n+1,cmpy); for(i=1;i<=n;i++) ly[p[i].id]=ly[p[i-1].id]+(p[i].b-p[i-1].b)*(i-1); for(i=n;i>=1;i--) ry[p[i].id]=ry[p[i+1].id]+(p[i+1].b-p[i].b)*(n-i); ans=1e16; for(i=1;i<=n;i++) ans=min(ans,lx[i]+rx[i]+ly[i]+ry[i]); cout<<ans/2; return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。