给定n个点,选择给定列表中的一个点,使得到这一点的距离总和最小,与所有其他点相比。
以下列方式测量距离。
对于点(x,y),所有8个相邻点的距离为1。
(x+1,y)(x+1,y+1),(x+1,y-1),(x,y+1),(x,y-1),(x-1,y)(x-1,y+1),(x-1,y-1)
修改
更清楚的解释。
函数foo定义为
foo(point_a,point_b) = max(abs(point_a.x - point_b.x),abs(point_a.y - point_b.y))
找到一个点x,使得sum(list_of_points中的y的[foo(x,y)]最小。
实施例
输入:
12 -14
-3 3
-14 7
-14 -3
2 -12
-1 -6
输出
-1 -6
例如: (4,5)和6,7之间的距离是2.
这可以通过检查每对的总和在O(n ^ 2)时间内完成。 有没有更好的算法呢?
答案 0 :(得分:5)
更新:有时候无法找到最佳状态,我会把它留在这里,直到找到问题为止。
这是O(n)
:nth是O(n)(预期,而不是最差),迭代列表是O(n)。如果你需要严格的O()然后选择带有排序的中间元素,那么它将是O(n * log(n))。
注意:很容易修改它以返回所有最佳点。
import sys
def nth(sample, n):
pivot = sample[0]
below = [s for s in sample if s < pivot]
above = [s for s in sample if s > pivot]
i, j = len(below), len(sample)-len(above)
if n < i: return nth(below, n)
elif n >= j: return nth(above, n-j)
else: return pivot
def getbest(li):
''' li is a list of tuples (x,y) '''
l = len(li)
lix = [x[0] for x in li]
liy = [x[1] for x in li]
mid_x1 = nth(lix, l/2) if l%2==1 else nth(lix, l/2-1)
mid_x2 = nth(lix, l/2)
mid_y1 = nth(liy, l/2) if l%2==1 else nth(liy, l/2-1)
mid_y2 = nth(liy, l/2)
mindist = sys.maxint
minp = None
for p in li:
dist = 0 if mid_x1 <= p[0] <= mid_x2 else min(abs(p[0]-mid_x1), abs(p[0]-mid_x2))
dist += 0 if mid_y1 <= p[1] <= mid_y2 else min(abs(p[1]-mid_y1), abs(p[1]-mid_y2))
if dist < mindist:
minp, mindist = p, dist
return minp
它基于一维问题的解决方案 - 对于一个数字列表,找到一个总和距离最小的数字。
如果列表中有偶数个元素,则解决方法是(已排序)列表的中间元素或两个中间元素(包括这两个元素)之间的任何数字。
更新:我的nth
算法似乎非常慢,可能有更好的方法来重写它,sort
优于&lt; sort(lix); sort(liy);
。 100000个元素,因此如果您进行速度比较,只需添加def nth(sample, n):
return sample[n]
和
import random
def example(length):
l = []
for x in range(length):
l.append((random.randint(-100, 100), random.randint(-100,100)))
return l
def bruteforce(li):
bestsum = sys.maxint
bestp = None
for p in li:
sum = 0
for p1 in li:
sum += max(abs(p[0]-p1[0]), abs(p[1]-p1[1]))
if sum < bestsum:
bestp, bestsum = p, sum
return bestp
对于那些想要测试他的解决方案的人,这是我使用的。只需运行一个循环,生成输入并将您的解决方案与bruteforce的输出进行比较。
{{1}}
答案 1 :(得分:1)
我可以想象一个比O(n ^ 2)好的方案,至少在通常的情况下。
从输入点构建quadtree。对于树中的每个节点,计算该节点内各点的数量和平均位置。然后,对于每个点,您可以使用四叉树在不到O(n)的时间内计算到所有其他点的距离。如果你计算从点p到远处四叉树节点v的距离,并且v不与p的45度对角线重叠,那么从p到v中所有点的总距离很容易计算(对于v它们在水平方向上比垂直方向与p分开,它只是v.num_points * |p.x - v.average.x|
,类似地使用y坐标,如果v主要是垂直分离的)。如果v与45度对角线中的一个重叠,则递归其组件。
那应该击败O(n ^ 2),至少当你找到一个平衡的四叉树来代表你的分数时。