高效最长算术进程的线性点集

2 投票
3 回答
759 浏览
提问于 2025-04-17 08:42

一组数字 {ab1, ab2, ab3 .... abn} 中的最长等差数列被定义为一个子集 {bb1, bb2, bb3 .... bbn},其中 bi+1 - bi 是一个固定的常数。

我想把这个问题扩展到一组位于直线上的二维点。我们定义 Dist(P1, P2) 为两个点 P1(X1, Y1) 和 P2(X2, Y2) 之间的距离,计算公式为:

Dist(P1, P2) = Dist((X1, Y1), (X2, Y2)) = (X2 - X1)2 + (Y2 - Y1)2

现在,对于给定的一组点,我需要找到最大的等差数列,使得 Dist(Pi, Pi+1) 是一个固定的值,假设它们都在同一条直线上(m 和 C 是常数)。

我查了一些资料,但没有找到比 O(n2) 更好的算法。

实际上,我现在的做法是维护一个字典,比如说:

DistDict=dict()

而点则定义在一个列表中:

Points = [(X1,Y1),(X2,Y2),....]

然后我做的就是:

for i,pi in enumerate(Points):
    for pj in Points[i+1:]:
         DistDict.setdefault(dist(pi,pj),set([])).add((pi,pj))

所以我最终得到了一个字典,里面存储的是等距离的点。接下来我只需要扫描一下,找出最长的 set

我在想,这个问题应该有更好的解决方案,但我就是想不出来。我也看过几个类似的旧帖子,但没有找到比 O(n2)更有效的方案。这个问题难道是 NP 难题,以至于我们永远无法找到更好的解决方案,还是说有其他的解决思路呢?

顺便提一下,我看到有个帖子提到了一种高效的 分治算法,但我看不太懂。

在这方面有什么帮助吗?

注意*** 我标记这个问题为 Python,因为我对 Python 比较熟悉,可能不太懂 Matlab 或 Ruby。C/C++/Java 也可以,因为我对这些也有一定的了解 :-)

3 个回答

1

首先,你对距离的定义是错的。你需要计算平方根。其次,如果你知道所有的点都在一条直线上,你可以简单地忽略y坐标(除非这条线是竖着的)或者x坐标(除非这条线是横着的)。这样问题就变得和你第一段说的那样简单了。

1

你可以研究一下快速傅里叶变换的方法,这是一种用于乘法运算的技术,效率是O(N log N)。

也许你可以用类似的方法来解决你遇到的问题。

1

总结一下:正如@TonyK提到的,如果你假设这些点在一条直线上,那么你可以把问题简化成一维的情况,这在这里已经讨论得很透彻。这个解决方案使用了快速傅里叶变换,正如@YochaiTimmer所提到的。

补充说明:这个问题几乎肯定不是NP难题,因为它有一个高效的O(n log n)解决方案,这就意味着P=NP。

撰写回答