题目地址: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|
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值和的最小值即可。
#include
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;
}