【问题标题】:Find distance between 2 points on grid查找网格上两点之间的距离
【发布时间】:2016-04-13 11:44:36
【问题描述】:

在给定departure = [x,y]destination = [x,y] 的情况下,我正在寻找两点之间的距离。对于 x 或 y,一个始终是浮点数,另一个是整数,因此它始终在一条线上。您必须停留在网格线上才能到达目标点,并且没有设置增量。我还没有看到任何其他关于在网格上找到处理整数和浮点数混合的距离的帖子,所以我在这里。

这是我的代码:

def perfectCity(departure, destination):
    return abs(destination[0]-departure[0]) + abs(destination[1]-departure[1]) 

一个例子是departure = [0.4, 1]destination = [0.9, 3],它应该等于 2.7,但我得到 2.5

例如,您从 [0.4, 1][1, 1][1, 3][0.9, 3] 的总差值为 2.7。这就像计算曼哈顿距离,但不是在格点开始和结束,而是在一个街区的中途开始和/或结束。

【问题讨论】:

  • 浮点数几乎总是有一点舍入误差。以 10 为底的有限小数展开并不总是以 2 为底的有限小数展开
  • 我不认为它是重复的,因为你必须知道它是一个浮点错误,在另一个线程中它是显式的。
  • 只能有一个线程解决浮点错误?
  • 那么——这不是曼哈顿距离(绝对是 2.5 而不是 2.7)。有些事情你没有告诉我们(也许运动仅限于 1.0 的倍数的网格线?)。在这种情况下,2.5 和 2.7 之间的差异与舍入误差无关,而是问题要求的内容与您尝试计算的内容之间的冲突。我将撤回我的近距离投票,但您应该编辑您的问题以更好地传达实际问题。

标签: python algorithm distance


【解决方案1】:

当您查看不同的组合时,似乎天真的曼哈顿距离会起作用,除了当您的路径呈“C”形时(如示例中所示)。当且仅当您的两个浮点数都是 x 坐标或 y 坐标并且具有相同的整数部分时,才会发生这种情况。

尝试可能如下所示:

def minimum_distance(p1, p2):

    i1, i2 = int(p1[0]), int(p2[0])

    # if both x-coordinates are floats and they have the same integer part
    if i1 != p1[0] and i2 != p2[0] and i1 == i2:

        # find the decimal parts
        d1, d2 = p1[0] - i1, p2[0] - i2

        # find the smaller "C"
        x = min(d1 + d2, (1-d1) + (1-d2))

        # add the y distance to the "C" distance
        return abs(p1[1] - p2[1]) + x

    # repeat with the "y-coordinates are floats" case
    i1, i2 = int(p1[1]), int(p2[1])
    if i1 != p1[1] and i2 != p2[1] and i1 == i2:
        d1, d2 = p1[1] - i1, p2[1] - i2
        y = min(d1 + d2, (1-d1) + (1-d2))
        return abs(p1[0] - p2[0]) + y

    # simple case, return the Manhattan distance
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])


print(minimum_distance([0.4, 1], [0.9, 3]))
# 2.7

【讨论】:

  • 很好的洞察力,x 在一个点上浮动而在另一个点上为 int 的情况简化为简单的出租车。
【解决方案2】:

从每个房子乘坐短程出租车到一个角落。你有两种方法可以这样做。然后——在产生的弯道之间乘坐长途出租车。有 2x2 = 4 种可能性,具体取决于所经过的角落。采取分钟:

from math import ceil,floor

#as a helper function, vanilla taxicab:

def t(p,q):
    x,y = p
    z,w = q
    return abs(x-z)+abs(y-w)

#find the two corners closest to a point:

def corners(p):
    x,y = p
    if isinstance(x,float):
        return [(floor(x),y),(ceil(x),y)]
    else:
        return [(x,floor(y)), (x,ceil(y))]

#combine these:   

def dist(p,q):
    return min(t(p,c) + t(c,d) + t(d,q)  for c in corners(p) for d in corners(q))

例如,

>>> dist((.4,1),(.9,3))
2.7

【讨论】:

  • 非常干净。它的效率不是很高,因此如果必须重复使用,可能值得优化。
  • 时机可能很有趣。似乎无论您需要至少 3 个案例,所以我决定只找到所有案例,然后让 min 操作员选择哪一个。内置运算符是用 C 编写的,因此不清楚这条路线是否比明确决定使用哪种情况要慢。我怀疑我的方法在困难的情况下比你的更快,但在简单的情况下肯定比你的慢,因为它简化为简单的出租车,所以很难说最终结果是什么。
  • 从一些简单的测试来看,我的函数在困难的情况下似乎快了 4 倍,在简单的情况下甚至更快。这看起来很自然,因为我的函数只计算曼哈顿距离一次而不是四次。虽然需要考虑三种情况,但无需实际执行“繁重”计算即可快速消除它们。
  • 另外,我不确定“内置运算符用 C 编写”的理由是否合适。例如,对于两个值,使用 a if a < b else b 比使用 min(a,b) 快​​两倍。简单的算术也被推回到C层并且它避免了相对昂贵的函数调用。
  • @JaredGoguen 你是对的。使用 Python 可以很容易地编写出不是特别高效的优雅代码。可以说它是 Python 的一个特性而不是一个错误,因为(与 C 相比)目标更多地是优化开发人员时间而不是 CPU 时间。尽管如此,效率通常很重要,如果需要将函数应用于大量点,我的代码中的函数调用开销将使其成为一个糟糕的选择。
【解决方案3】:

这不是intfloat 的混合,可能您遇到了浮点错误。 floats 不准确,它们是近似值,因此可以“偏离”少量。

您可以使用decimal 模块提供的Decimal 对象来准确处理浮点值。这是一个例子:

>>> 1.1 + 2.2        # will produce small error
3.3000000000000003
>>> from decimal import Decimal
>>> Decimal('1.1') + Decimal('2.2')
Decimal('3.3')

最终结果仍将是“关闭”,但使用Decimal 将有助于避免累积舍入误差:

>>> 3.3 - (1.1 + 2.2)
-4.440892098500626e-16
>>> Decimal(3.3) - (Decimal(1.1) + Decimal(2.2))
Decimal('-4.440892098500250464677810669E-16')
>>> Decimal('3.3') - (Decimal('1.1') + Decimal('2.2'))
Decimal('0.0')

【讨论】:

  • 偏离超过一两点,有时偏离 0.2 - 0.6
  • @JonnyDoeInWisco:是的,每次浮点运算都会累积错误。使用Decimal 对象应该可以减少累积错误。
  • @JonnyDoeInWisco 如果错误对于典型大小的输入来说那么大,我会感到惊讶。也许您可以编辑您的问题,并展示一个您认为无法用较小的舍入错误来解释的任何错误的示例。
  • 投反对票是不公平的,因为这是对原始问题的一个很好的回答(没有编辑得面目全非),所以 +1
猜你喜欢
  • 2019-09-16
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-20
  • 2015-11-19
  • 2022-08-14
  • 1970-01-01
相关资源
最近更新 更多