【bzoj3170】[Tjoi2013]松鼠聚会

3170: [Tjoi2013]松鼠聚会

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1670  Solved: 885
[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

HINT

 

Source

 
[Submit][Status][Discuss]
 
题意:N个点,求某一个点到其他点的切比雪夫距离之和最小化;
题解:
        推荐一篇页面比较好讲得很清楚的博客:https://www.cnblogs.com/zwfymqz/p/8253530.html
        两个点(x1,y1) 和 (x2,y2)
        切比雪夫距离:max(|x1-x2|,|y1-y2|)
        曼哈顿距离:|x1-x2|+|y1-y2|
        先介绍绝对值的两个性质:|a|+|b| = max(|a+b|,|a-b|)  max(|a|,|b|) = |(a+b)/2|+|(a-b)/2|
        可以利用数轴理解一下;
        利用上面的性质可以知道:
        若:(x,y) – > (x-y,x+y) 则新图的切比雪夫距离为原图的曼哈顿距离;
        若:(x,y) – > ((x-y)/2,(x+y)/2) 则新图的曼哈顿距离为原图的切比雪夫距离;
        为什么要转化呢?
        切比雪夫不好处理,转化后对曼哈顿距离分x,y排序,预处理某个值到前面的曼哈顿距离之和,可以做到O(1)查询,此题直接枚举哪个点;
        另外如果最近的点不要求在这些点里面而是平面的任何一个点,分别贪心选取x坐标,y坐标的排序后的中位数,注意切比雪夫转曼哈顿,有可能不是整点,要求整点还需要特判一下;
 
 1  
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<queue>
 7 #include<cmath>
 8 #include<vector>
 9 #include<stack>
10 #include<map>
11 #define Run(i,l,r) for(int i=l;i<=r;i++)
12 #define Don(i,l,r) for(int i=l;i>=r;i--)
13 #define ll long long
14 #define inf 0x3f3f3f3f
15 using namespace std;
16 const int N=100010;
17 int n,px[N],py[N];
18 ll upx[N],dnx[N],upy[N],dny[N];
19 struct data{
20     int x,id;
21     bool operator <(const data&A)const{
22         return x<A.x;
23     }
24 }X[N],Y[N];
25 int main(){
26 //  freopen("bzoj3170.in","r",stdin);
27 //  freopen("bzoj3170.out","w",stdout);
28     scanf("%d",&n);
29     for(int i=1;i<=n;i++){
30         int a,b;
31         scanf("%d%d",&a,&b);
32         X[i]=(data){a-b,i};
33         Y[i]=(data){a+b,i};
34     }
35     sort(X+1,X+n+1);
36     sort(Y+1,Y+n+1); 
37     for(int i=1;i<=n;i++){
38         px[X[i].id]=i;
39         py[Y[i].id]=i;      
40     } 
41     ll ans=1e18;
42     for(int i=1;i<=n;i++){
43         upx[i]=upx[i-1]+1ll*(i-1)*(X[i].x-X[i-1].x);
44         upy[i]=upy[i-1]+1ll*(i-1)*(Y[i].x-Y[i-1].x);
45     }
46     for(int i=n;i;i--){
47         dnx[i]=dnx[i+1]+1ll*(n-i)*(X[i+1].x-X[i].x);
48         dny[i]=dny[i+1]+1ll*(n-i)*(Y[i+1].x-Y[i].x);
49     }
50     for(int i=1;i<=n;i++){
51         ans=min(ans,upx[px[i]]+dnx[px[i]]+upy[py[i]]+dny[py[i]]);
52     }
53     printf("%lld\n",ans>>1);
54     return 0;
55 }//by tkys_Austin;
View Code

 

 

转载于:https://www.cnblogs.com/Paul-Guderian/p/9814343.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值