这是一个编程竞赛问题。我只是在寻求建议,因为这只是为了练习而不是为了作弊等目的。
问题是我有一组数千个点,它们有一个x和y坐标(在10 ^ -10到10 ^ 10之间)。我必须发现,如果存在任何共线的4个点,即位于直线上。
到目前为止,我所想到的是以下内容:
每对点,将y2-y1 / x2-x1存储在地图中,其中斜率为关键点,点列表为值。 存储后,查看地图中是否已存在相同的值,以及这对点是否与您当前处理的点不同。如果它们不同,那么你就有了4个共线点。
但是,此问题的空间和时间复杂度为O(N ^ 2)。而且,这涉及大量的小数和除法运算,这降低了准确性。
有人能为这个问题提出更优雅的解决方案吗?
谢谢, 乌代
答案 0 :(得分:2)
您可以使用Hough transform执行此操作。
基本上,对于每个点( x , y ),您可以考虑通过这一点的每条可能的线。
每一行都可以用两个参数来描述:
我将在下面使用ρ和θ。
通过将ρ和θ四舍五入到给定的精度,可以确保每个点都有有限数量的可能线。如果以10 8 的步长测量ρ,则ρ只有282个可能值(因为最大 x 和 y 坐标为10 < SUP> 10 )。如果以整度测量θ,则θ只有180个可能的值。
因此,您可以在由(ρ,θ)索引的二维数组中表示每条可能的线。这称为累加器数组。让我们存储属于该数组中给定行的点数:
int[,] accumulator = new int[numRho, numTheta]
for each point (x,y):
for θ from 0° to 179°:
ρ = x cos θ + y sin θ
ρ = ρ / 10^8
accumulator[ρ, θ] ++
现在我们只需要检查累加器值为4或更多的桶,这意味着其中一条线上可能有四个或更多点落入该桶。当然,由于我们舍入ρ和θ,我们需要检查这些点是否真的位于同一条线上(这里我们可以使用天真的O( n 2 )算法,或者如果找到的点数很大,我们可以用更精细的ρ和θ细分重复这个算法。
for each possible ρ
for each possible θ
if accumulator[ρ, θ] >= 4
find all points in that bucket that are close to the line (ρ, θ)
check those points for collinearity
如果我们选择ρ和θ的分辨率足够大,大多数桶包含的四个点少,那么我们应该有一个摊销的复杂性:
否则我们需要一个更大的累加器数组。不过,我认为这应该比测试每一对点要快得多。
答案 1 :(得分:0)
对于每个点,Pi具有一组矢量V,表示从Pi到彼此的点Qj的连接,其中i <1。记者: 如果集合V中存在三个共线矢量,则点是共线的。 (共线测试是一个简单的vector_product)。
最差情况运行时间复杂度:O(n(n + 1)(n + 2)/ 6)== O(n ^ 3) 空间复杂度:O(1)
// Having a class Point, Vector and a function vector_product
typedef std::vector<Point> Points;
bool find_four_collinear_points(const Points& points) {
for(unsigned i0 = 0; i0 < points.size(); ++i0) {
const Point& p0 = points[i0];
for(unsigned i1 = i0 + 1; i1 < points.size(); ++i1) {
const Point& p1 = points[i1];
if(p0 == p1) continue;
unsigned collinear = 0;
for(unsigned i2 = i1 + 1; i2 < points.size(); ++i2) {
const Point& p2 = points[i2];
if(p0 == p2) continue;
if(p1 == p2) continue;
if(vector_product(Vector(p0, p1), Vector(p1, p2)) == 0) {
if(++collinear == 3)
return true;
}
}
}
}
return false;
}
答案 2 :(得分:-1)
我发现这个问题的解决方案在O(n ^ 2)中运行,可能是最简单的解决方案。您可以使它更有效,但我认为大多数迭代解决方案都是这种形式。 (它在python中)
def slope(p1,p2):
if int(p2[0]-p1[0]) is 0:
return False
m = (p2[1]-p1[1])/(p2[0]-p1[0])
return m
def fourOnALine(listoftuples):
n = len(listoftuples)
for i in range(n):
slope_dict = {}
count = 0
for j in range(i+1,n):
m = slope(listoftuples[i], listoftuples[j])
if m in slope_dict:
slope_dict[m]+= 1
else:
slope_dict[m] = 1
for key in slope_dict:
if slope_dict[key] == 3:
return True
return False
print fourOnALine([(1,1),(2,2),(3,3),(8,8)])#true
print fourOnALine([(5.0,1.0),(5.0,8.0),(3.0,4.0),(7.0,12.0),(-3.0,6.0),(1.0,0.0)])#true
print fourOnALine([(3,9),(-4,9),(0,2),(1,-3),(5,4)])#false
print fourOnALine([(-1000.0,1000.0),(-2000.0,1000.0),(-3000.0,999.0),(-4000.0,1000.0)])#false