[BZOJ 3170][Tjoi 2013]松鼠聚会

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^9

Output

表示为了聚会走的路程和最小为多少。

Sample Input

6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2

Sample Output

20

题解

我们可以发现, 我们走过一个对角线的距离也记为 $1$ , 这样的话我们可以直接补偿掉任意两个点间横坐标差与纵坐标差之间的差, 也就是说两点间的距离是这样的:

\[max(|x_0-x_1|,|y_0-y_1|)\]

实际上这是切比雪夫距离的定义, 但是单纯求所有其他点到某个点的切比雪夫距离和比较困难, 我们可以考虑按照一定规则转换点的坐标来使点与点间的曼哈顿距离等于原来的点之间的切比雪夫距离, 具体转换方式为 $(x,y) \rightarrow (x+y,x-y)$ , 转化前两点的切比雪夫距离为转化后两点间的曼哈顿距离的一半. 正确性很容易证明.

转化为曼哈顿距离后, 我们可以对所有横坐标排序并求前缀和, 然后对所有纵坐标排序求前缀和, 用前缀和减去目标的最终位置再求绝对值即可得到结果.

参考代码

GitHub

 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\n",sum);
47         ans=std::min(ans,sum);
48     }
49     printf("%lld\n",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 }
Backup

 

 

posted @ 2017-10-17 21:18  rvalue  阅读(281)  评论(0编辑  收藏  举报