题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4312

必备知识:https://www.cnblogs.com/zwfymqz/p/8253530.html

二维坐标轴上两点:A(x1,y1) B(x2,y2)

切比雪夫距离:disq = max(|x1-x2|, |y1-y2|)

曼哈顿距离:dism = |x1-x2|+|y1-y2|

切比雪夫距离--->曼哈顿距离:(x,y)变换为(  ,  )

证明:A(0,0) B(x,y)  C(  ,  )

AB之间的切比雪夫距离disq = max(|x|,|y|) ,AC之间的曼哈顿距离dism = |  |  +| |

(1)当x>0且y>0时 :dism = max(x,y),disq = max(x,y)

(2)当x<0且y<0时:dism = max(|x|,|y|), disq = max(|x|, |y|)

当x异号时,dism和disq也是等价的。(我懒得打字了。。)

曼哈顿距离--->切比雪夫距离:(x,y)变换为(x+y, x-y)

证明方法同上,分情况讨论一下就好了。

 

题目:


给出二维坐标轴上的一些点,要找到一个点,使其他点到它的切比雪夫距离之和最小,求最小的距离和

 

解题思路:


因为切比雪夫距离求解的时候是max(||,||)的形式,不仅要消除绝对值的影响,而且还要去个max,求起来比较麻烦。

将切比雪夫距离转化为曼哈顿距离,这样就只需要消除绝对值的影响了。

将输出的点先按照x值从小到大排序,记录x的前缀和和后缀和,为了消除绝对值的影响,每次求解曼哈顿距离是都让排名靠后的数-排名靠前的数。这样就可以求出来某个点和其他点的x值距离之和。

比如:x排完序为:-4,-3,-2,0,4,5,(下标从1开始)当求解其他点到x值第三小的这个点(x=-2这个点)时,

dism = |-2-(-4)| + |-2-(-3)|     +  |0-(-2)| + |4-(-2)| + |5-(-2)| 

      = (-2)* 2  - ((-4)+(-3))  +    ( 0 + 4 + 5 )- (-2) *  3

      =  (-2)* ( i - 2) - pre_sum[ i - 1 ]    +   suf_sum[ i + 1 ] - (-2)* ( n  -  i )

再把点按照y值从小到大排序,用同样的方法求出某个点和其他点的y值距离之和

最终求距其他点x值和+y值和的最小值即可。

 

ac代码:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
struct node
{
    ll p[2];
    int pos;
} a[maxn];

int n;
ll sum[maxn][2];
ll ans[maxn];

void solve(int x)
{
    for(int i = 1;i<= n;i++)
        sum[i][0] = a[i].p[x]+sum[i-1][0];//前缀和
    for(int i = n;i>= 1;i--)
        sum[i][1] = a[i].p[x]+sum[i+1][1];//后缀和

    for(int i = 1;i<= n;i++)
        // 前面到ta的x/y绝对值距离之和 + 后面的到它的绝对值距离之和
        ans[a[i].pos]+= a[i].p[x]*(i-1)-sum[i-1][0] + sum[i+1][1]-a[i].p[x]*(n-i);
}
bool cmp1(node x,node y)
{
    return x.p[0]< y.p[0];
}
bool cmp2(node x,node y)
{
    return x.p[1]< y.p[1];
}

int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        memset(sum, 0 ,sizeof(sum));
        scanf("%d",&n);
        for(int i = 1;i<= n;i++)
        {
            ll x,y;
            scanf("%lld %lld",&x,&y);
            a[i].p[0] = x+y;
            a[i].p[1] = x-y;
            a[i].pos = i;
            ans[i] = 0;
        }

        sort(a+1,a+n+1,cmp1);
        solve(0);
        sort(a+1,a+n+1,cmp2);
        solve(1);

        ll m = ans[1];
        for(int i = 2;i<= n;i++)
            m = min(m,ans[i]);

        printf("%lld\n",m/2);
    }

    return 0;
}