3170: [Tjoi 2013]松鼠聚会
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1346 Solved: 681
[Submit][Status][Discuss]Description
有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。
Input
第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5
下面N行,每行给出x,y表示其家的坐标。
-10^9<=x,y<=10^9Output
表示为了聚会走的路程和最小为多少。
Sample Input
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2Sample Output
20
题解
我们可以发现, 我们走过一个对角线的距离也记为 $1$ , 这样的话我们可以直接补偿掉任意两个点间横坐标差与纵坐标差之间的差, 也就是说两点间的距离是这样的:
[max(|x_0-x_1|,|y_0-y_1|)]
实际上这是切比雪夫距离的定义, 但是单纯求所有其他点到某个点的切比雪夫距离和比较困难, 我们可以考虑按照一定规则转换点的坐标来使点与点间的曼哈顿距离等于原来的点之间的切比雪夫距离, 具体转换方式为 $(x,y) ightarrow (x+y,x-y)$ , 转化前两点的切比雪夫距离为转化后两点间的曼哈顿距离的一半. 正确性很容易证明.
转化为曼哈顿距离后, 我们可以对所有横坐标排序并求前缀和, 然后对所有纵坐标排序求前缀和, 用前缀和减去目标的最终位置再求绝对值即可得到结果.
参考代码
1 #include <cstdio> 2 #include <cstring> 3 #include <climits> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 8 const int MAXN=1e5+10; 9 10 struct Point{ 11 long long x; 12 long long y; 13 long long posx; 14 long long posy; 15 }; 16 17 int n; 18 long long sx[MAXN]; 19 long long sy[MAXN]; 20 21 Point P[MAXN]; 22 23 void Initialize(); 24 bool cmpx(const Point&,const Point&); 25 bool cmpy(const Point&,const Point&); 26 27 int main(){ 28 Initialize(); 29 std::sort(P+1,P+n+1,cmpx); 30 for(int i=1;i<=n;i++){ 31 P[i].posx=i; 32 sx[i]=sx[i-1]+P[i].x; 33 } 34 std::sort(P+1,P+n+1,cmpy); 35 for(int i=1;i<=n;i++){ 36 P[i].posy=i; 37 sy[i]=sy[i-1]+P[i].y; 38 } 39 long long ans=LLONG_MAX; 40 for(int i=1;i<=n;i++){ 41 long long sum=0; 42 sum+=P[i].x*(P[i].posx)-sx[P[i].posx]; 43 sum+=sx[n]-sx[P[i].posx]-(n-P[i].posx)*P[i].x; 44 sum+=P[i].y*(P[i].posy)-sy[P[i].posy]; 45 sum+=sy[n]-sy[P[i].posy]-(n-P[i].posy)*P[i].y; 46 // printf("%lld ",sum); 47 ans=std::min(ans,sum); 48 } 49 printf("%lld ",ans/2); 50 return 0; 51 } 52 53 void Initialize(){ 54 int x,y; 55 scanf("%d",&n); 56 for(int i=1;i<=n;i++){ 57 scanf("%d%d",&x,&y); 58 P[i].x=x+y; 59 P[i].y=x-y; 60 } 61 } 62 63 inline bool cmpx(const Point& x,const Point& y){ 64 return x.x<y.x; 65 } 66 67 inline bool cmpy(const Point& x,const Point& y){ 68 return x.y<y.y; 69 }