📌  相关文章
📜  所有点对之间的曼哈顿距离之和(1)

📅  最后修改于: 2023-12-03 15:39:40.242000             🧑  作者: Mango

所有点对之间的曼哈顿距离之和

曼哈顿距离是指在规定的坐标系下,两个点横坐标差的绝对值加上纵坐标差的绝对值,即$|x_1-x_2|+|y_1-y_2|$。曼哈顿距离相比于欧几里得距离更符合在城市街区中寻找最短路径的实际情况,因为在城市街区中不能直线行走。

给定平面上的$n$个点,求所有点对之间曼哈顿距离之和。

解法

$n\leq 10^5$的复杂度应该在$O(n\log n)$到$O(n^2)$之间,显然不能让所有点对求一遍曼哈顿距离之后累加起来。考虑如何简化计算。

设一个点为$(x_i,y_i)$,则以该点为起点,所有点对之间的曼哈顿距离之和为:

$$\sum_{j=1}^{i-1}(x_i-x_j)+(y_i-y_j)+\sum_{j=i+1}^n(x_j-x_i)+(y_j-y_i)$$

$$=i\times x_i-\sum_{j=1}^{i-1}x_j+\sum_{j=i+1}^nx_j+i\times y_j-\sum_{j=1}^{i-1}y_j+\sum_{j=i+1}^ny_j-n\times x_i-n\times y_i$$

设$x$轴上的点按$x$坐标从小到大排序,$y$轴上的点按$y$坐标从小到大排序,则:

$$\sum_{i=1}^n\sum_{j=i+1}^n|x_i-x_j|+|y_i-y_j|$$

$$=\sum_{i=1}^n\sum_{j=i+1}^n[(x_i-x_j)+(y_i-y_j)]$$

$$=\sum_{i=1}^ni\times x_i-\sum_{i=1}^n\sum_{j=1}^{i-1}x_j+\sum_{i=1}^n\sum_{j=i+1}^nx_j+i\times y_j-\sum_{i=1}^n\sum_{j=1}^{i-1}y_j+\sum_{i=1}^n\sum_{j=i+1}^ny_j-n\sum_{i=1}^nx_i-n\sum_{i=1}^ny_i$$

$$=(n-1)\sum_{i=1}^nx_i+(n-1)\sum_{i=n}^nx_i+(n-1)\sum_{i=1}^ny_i+(n-1)\sum_{i=n}^ny_i$$

$$=2(n-1)\sum_{i=1}^nx_i+2(n-1)\sum_{i=1}^ny_i$$

代码实现
def manhattan_distance(points: List[Tuple[int, int]]) -> int:
    """
    计算平面上所有点对之间曼哈顿距离之和
    Args:
        points: 点的坐标列表,其中每个元素为一个二元组,表示点的坐标

    Returns:
        所有点对之间曼哈顿距离之和
    """
    n = len(points)
    x = [p[0] for p in points]
    y = [p[1] for p in points]
    x.sort()
    y.sort()
    return 2 * ((n - 1) * sum(x) + (n - 1) * sum(y))

以上代码中,首先获取所有点的$x$坐标和$y$坐标,并对它们从小到大排序。然后按上面的公式进行计算即可。

总结

本题虽然看似简单,但需要引入一些数学知识后才能想到优化计算方法。同时,代码实现也需要注意细节。