计算给定曼哈顿距离的点对数

时间:2018-10-20 16:22:02

标签: algorithm math geometry

我有 P 个点,它们的整数坐标(用(xi,yi)表示)。

0 <= xi <= n; 0 <= yi <= m (i = 1,2 ... P)

2 <= n,m <= 100

我很想找出相距 d 的点对数。显然,1 <= d <= m + n-2和P <= m * n。我想计算每个 d 的对数。最快的方法是什么? (我可以通过遍历d并为每个d检查每一对来找到它。这是非常缓慢的过程)

e.g.
points : (0,2);(0,3);(2,1)
for d=1 : 1 pair
for d=2 : 0 pairs
for d=3 : 1 pair
for d=4 : 1 pair
for d=5 : 0 pairs

2 个答案:

答案 0 :(得分:1)

为什么不循环遍历所有点对并计算距离,并创建一个以键为距离和值为频率的地图?

for point P1 in P
   for point P2 in P, P2 > P1
      d <- distance(P1,P2) 
      if (mapDistance.get(d) exists)
         increment mapDistance.get(d)
      else 
         mapDistance.put(d,1)

总体复杂度为O(P * P)

答案 1 :(得分:0)

以下是具有N×M复杂度的算法,用于获取单个距离d的点对数。要获得所有距离的总和,请对d的每个值运行此算法。这样,总体复杂度将为N×M×(N + M),应符合时间约束。

(有一些替代方法;您可以构建一个网格,每个对角线的总和为1,然后减去两个数,以距离某一点的距离d读出每个对角线的1的个数。相似的理论复杂度,但实际上可能更快。)


(我们将使用给定的输入作为二进制网格,就像在CodeChef上的原始问题一样,而不是您建议的坐标列表。)

让我们看一下曼哈顿距离的几何:

 6 5 4 3 4 5 6
 5 4 3 2 3 4 5
 4 3 2 1 2 3 4
 3 2 1 X 1 2 3
 4 3 2 1 2 3 4
 5 4 3 2 3 4 5
 6 5 4 3 4 5 6

您会注意到,距离d处的点在对角线上,在该点周围形成菱形,其中有4 d个。例如对于距离d = 3:

       3
     3 . 3
   3 . . . 3
 3 . . X . . 3
   3 . . . 3
     3 . 3
       3

我们不想对每一对都计算两次,因此我们只看一下钻石四个侧面中的两个:

       A
     . . A
   . . . . A
 . . . X . . B
   . . . . B
     . . B
       .

如果中心点X的值为1,则可以将点A和B的值的总和添加到距离d的对的总数中。

我们可以遍历网格以找到两个对角线运动的总和;首先,让我们检查每个点周围菱形右上角的点A。我们看一下彼此相距d的对角线,例如对于距离为3的7×6网格:

 . . . . . . .     . . . . . . .     A . . . . . .     . A . . . . .
 . . . . . . .     A . . . . . .     . A . . . . .     . . A . . . .
 A . . . . . .     . A . . . . .     . . A . . . .     X . . A . . .
 . A . . . . .     . . A . . . .     X . . A . . .     . X . . A . .
 . . A . . . .     X . . A . . .     . X . . A . .     . . X . . A .
 X . . A . . .     . X . . A . .     . . X . . A .     . . . X . . A     etc...

对于每一个,我们迭代X对角线,如果点X的值为1,则将其上方的d点A的值之和加到总数中,例如:< / p>

 A . . . . . .     . . . . . . .     . . . . . . .
 . A . . . . .     . A . . . . .     . . . . . . .
 . . A . . . .     . . A . . . .     . . A . . . .
 X . . . . . .     . . . A . . .     . . . A . . .
 . . . . . . .     . X . . . . .     . . . . A . .
 . . . . . . .     . . . . . . .     . . X . . . .

如您所见,可以使用滑动窗口来计算d点A的值之和,因此我们只需要对每个对角线上的值进行一次迭代。

然后我们对另一个方向的对角线进行相同操作:

 X . . B . . .     . X . . B . .     . . X . . B .     . . . X . . B
 . . B . . . .     X . . B . . .     . X . . B . .     . . X . . B .
 . B . . . . .     . . B . . . .     X . . B . . .     . X . . B . .
 B . . . . . .     . B . . . . .     . . B . . . .     X . . B . . .
 . . . . . . .     B . . . . . .     . B . . . . .     . . B . . . .
 . . . . . . .     . . . . . . .     B . . . . . .     . B . . . . .     etc...

我们对每个对角线(在两个方向上)进行一次迭代,因此最终我们对每个点进行了两次迭代,并且算法的复杂度与M×N成线性关系。