曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。
切比雪夫距离是向量空间中的一种度量,二个点之间的距离定义为其各座标数值差绝对值的最大值。以(x1,y1)和(x2,y2)二点为例,其切比雪夫距离为max(|x2-x1|,|y2-y1|)。
大佬的讲解
曼哈顿距离 与 切比雪夫距离 之间会不会有联系呢?
设 A(x1,y1),B(x2,y2)
A,B 两点的曼哈顿距离为:|x1-x2|+|y1-y2|
=max{x1-x2+y1-y2,x1-x2+y2-y1,x2-x1+y1-y2,x2-x1+y2-y1}
=max{|(x1+y1)-(x2+y2)|,|(x1-y1)-(x2-y2)|}
易知A,B两点的曼哈顿距离即为(x+y,x-y)的切比雪夫距离;
同理,A,B两点的切比雪夫距离为:max{|x1-x2|,|y1-y2|}
=max{x1-x2,x2-x1,y1-y2,y2-y1}
=|(x1+y1)/2-(x2+y2)/2|+|(x1-y1)/2-(x2-y2)/2|
易知A,B两点的切比雪夫距离即为((x+y)/2,(x-y)/2))的曼哈顿距离;
求在二维坐标系中到所有点切比雪夫距离之和最小的点的数量和值;
在求距离之和上,切比雪夫距离并不好求,但是这题转化为曼哈顿距离相对来说就简单一些了。
将所有点转化为求曼哈顿距离的点,二维相对比较难求和,但本题可以分开在x上求和和在y上求和
分别对x排序和对y排序,选取中间区域的点,即为最小距离
需要注意的是由于是转化为曼哈顿距离的点,所以求点的数量需要转化回切比雪夫距离上的点
易知对于x+y和x-y可以得到唯一解,但x+y和x-y必定同偶或者同奇,否则无解。
具体分析见代码
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long int LL;
const int maxn = 100005;
const LL inf = 1e18;
#define abs(x) ((x)<0?-(x):(x))
int x[maxn], y[maxn];
int main() {
int n; cin>>n;
register int dx, dy;
for (int i = 1; i <= n; i++) {
cin>>dx>>dy;
x[i] = dx + dy; //转化为曼哈顿距离
y[i] = dx - dy;
}
sort(x + 1, x + 1 + n); //按x排序
sort(y + 1, y + 1 + n); //按y排序
LL ans = 0, cnt = 0; //距离和点数
if (n & 1) { //奇数个点
int mid = (n + 1) >> 1,
left = x[mid], right = y[mid];
if ((right - left) & 1) //如果同奇偶性则无解
cnt = 0;
else
cnt = 1;
}
else {
int mid = n >> 1;
LL l1 = x[mid], r1 = x[mid + 1], //预处理
l2 = y[mid], r2 = y[mid + 1],
len1 = abs(l1 - r1) + 1,
len2 = abs(l2 - r2) + 1,
leng1 = len1 >> 1,
leng2 = len2 >> 1;
if (len1 & 1) { //x轴奇数个点
if (len2 & 1) { //y轴奇数个点
if ((l1 - l2) & 1) { //两轴占大多数的元素奇偶性不同
cnt = leng1 * (leng2 + 1) + (leng1 + 1) * leng2;
}
else { //两轴占大多数的元素奇偶性相同
cnt = (leng1 + 1) * (leng2 + 1) + leng1 * leng2;
}
}
else { //y轴偶数个点
cnt = leng1 * leng2 + (leng1 + 1) * leng2;
}
}
else { //x轴偶数个点
if (len2 & 1) { //y轴奇数个点
cnt = leng1 * leng2 + leng1 * (leng2 + 1);
}
else { //y轴偶数个点
cnt = (leng1 * leng2) + (leng1 * leng2);
}
}
}
int mid = (n + 1) >> 1;
if (!cnt) { //点数为0,易知答案为距离最近的点
LL ex[4] = { -1,0,1,0 },
ey[4] = { 0,-1,0,1 }; //向四个方向搜索
ans = inf;
for (int i = 0; i < 4; i++) {
LL _X = x[mid] + ex[i],
_Y = y[mid] + ey[i],
sum = 0;
for (int i = 1; i <= n; i++)
sum += abs(_X - x[i]);
for (int i = 1; i <= n; i++)
sum += abs(_Y - y[i]);
if (sum < ans) //若为最小值,更新
cnt = 1, ans = sum;
else if (sum == ans)
cnt++;
}
printf("%lld\n%lld\n", ans >> 1, cnt);
}
else {
LL m = x[mid]; //x方向的曼哈顿距离
for (int i = 1; i < mid; i++)
ans += m - x[i];
for (int i = mid + 1; i <= n; i++)
ans += x[i] - m;
m = y[mid]; //y方向的曼哈顿距离
for (int i = 1; i < mid; i++)
ans += m - y[i];
for (int i = mid + 1; i <= n; i++)
ans += y[i] - m;
printf("%lld\n%lld\n", ans >> 1, cnt);
}
}