hdu_4311_Meeting point-1(曼哈顿距离)及其拓展

hdu_4311_Meeting point-1(曼哈顿距离)及其拓展

题目链接

题目描述

给定n个点,找出其中一个点,使得其他点到这个点的曼哈顿距离和最小,求这个最小距离和。

Sample Input

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

Sample Output

26
20
20
56

解题思路

曼哈顿距离:两个点的横纵坐标的差的绝对值之和;
d i c = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ dic=|x_1-x_2|+|y_1-y_2| dic=x1x2+y1y2
题目要求计算的结果为
d i c = ∑ i = 1 n ∣ x i − x ∣ + ∑ i = 1 n ∣ y i − y ∣ dic=\sum_{i=1}^n{|x_i-x|}+\sum_{i=1}^n{|y_i-y|} dic=i=1nxix+i=1nyiy
暴力解法就是,遍历所有点,计算其到其他所有点的曼哈顿距离和,记录最小值,时间复杂度是O( n 2 n^2 n2);
优化过程:预处理两个数组sum_x[n],sum_y[n];
sum_x[i]表示到序号i为止的点的横坐标的和。
sum_y[i]表示到序号i为止的点的纵坐标的和。
将所有点按x排序后:
s u m x = ∑ i = 1 n ∣ x i − x ∣ = ( i − 1 ) ∗ x [ i ] − s u m x [ i − 1 ] + s u m x [ n ] − s u m x [ i ] − ( n − i ) ∗ x [ i ] ; sum_x=\sum_{i=1}^n{|x_i-x|} =(i - 1)*x[i] - sum_x[i - 1] + sum_x[n] - sum_x[i] - (n - i)*x[i]; sumx=i=1nxix=(i1)x[i]sumx[i1]+sumx[n]sumx[i](ni)x[i];
将所有点按y排序后:
s u m y = ∑ i = 1 n ∣ y i − y ∣ = ( i − 1 ) ∗ y [ i ] − s u m y [ i − 1 ] + s u m y [ n ] − s u m y [ i ] − ( n − i ) ∗ y [ i ] ; sum_y=\sum_{i=1}^n{|y_i-y|} =(i - 1)*y[i] - sum_y[i - 1] + sum_y[n] - sum_y[i] - (n - i)*y[i]; sumy=i=1nyiy=(i1)y[i]sumy[i1]+sumy[n]sumy[i](ni)y[i];
时间复杂度为O(nlog(n));

AC代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int maxn=100005;
struct note
{
    int x,y,id;
} a[maxn];
int x[maxn],y[maxn],n;
LL numx[maxn],numy[maxn];

bool cmp1(note a,note b)
{
    return a.x<b.x;
}

bool cmp2(note a,note b)
{
    return a.y<b.y;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        LL sumx=0,sumy=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            a[i].x=x[i];
            a[i].y=y[i];
            a[i].id=i;
            sumx+=x[i];
            sumy+=y[i];
        }
        sort(a+1,a+n+1,cmp1);
        LL ans=0;
        for(int i=1; i<=n; i++)
        {
            ans+=a[i].x;
            int j=a[i].id;
            numx[j]=(LL)x[j]*(2*i-n)+sumx-2*ans;
        }
        sort(a+1,a+1+n,cmp2);
        ans=0;
        for(int i=1; i<=n; i++)
        {
            ans+=a[i].y;
            int j=a[i].id;
            numy[j]=(LL)y[j]*(2*i-n)+sumy-2*ans;
        }
        ans=numy[1]+numx[1];
        for(int k=2; k<=n; k++)
            ans=min(ans,numx[k]+numy[k]);
        printf("%I64d\n",ans);
    }
    return 0;
}

####扩展
给定n个点的坐标,求出一个点(不一定是n个点之一),使得其到其他所有点的曼哈顿距离和最小;
易知,要求的点的x值必定是n个点中某一个点的x值,y值必定是n个点中某一个点的y值,但未必是同一个点的x值和y值;求x和y的过程跟上面一题一样。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值