Найдите большинство точек включенным в круг фиксированного размера

Это подошло, когда друг говорил о соревновании по программированию и интересно, каков лучший подход был:

Учитывая список точек, найдите центр круга предопределенного размера, который отвечает на большинство вопросов. Если существуют несколько таких кругов, его единственное важное для нахождения одного из них.

Пример ввел: 1 000 точек, в 500x500 пространство и круг 60 диаметров.

11
задан Saeed Amiri 12 January 2017 в 00:08
поделиться

4 ответа

Мой лучший подход до сих пор:

каждый круг, содержащий точки, должен иметь левую точку. Таким образом, он делает список всех точек справа от точки, потенциально в пределах окружности. Сначала он сортирует точки X, чтобы сделать Sweep Sane.

Затем он снова сортирует их, на этот раз по количеству соседей справа, что у них есть, так что точка с большинством соседей сначала изучатся.

Затем он осматривает каждую точку, а для каждой точки справа он вычисляет круг, где эта пара точек находится на левом периметре. Затем это считает точки в таком круге.

Поскольку точки были отсортированы по потенциалу, он может заранее, когда он считается всеми узлами, которые могут потенциально привести к лучшему решению.

import random, math, time
from Tkinter import * # our UI

def sqr(x):
    return x*x

class Point:
    def __init__(self,x,y):
        self.x = float(x)
        self.y = float(y)
        self.left = 0
        self.right = []
    def __repr__(self):
        return "("+str(self.x)+","+str(self.y)+")"
    def distance(self,other):
        return math.sqrt(sqr(self.x-other.x)+sqr(self.y-other.y))

def equidist(left,right,dist):
    u = (right.x-left.x)
    v = (right.y-left.y)
    if 0 != u:
        r = math.sqrt(sqr(dist)-((sqr(u)+sqr(v))/4.))
        theta = math.atan(v/u)
        x = left.x+(u/2)-(r*math.sin(theta))
        if x < left.x:
            x = left.x+(u/2)+(r*math.sin(theta))
            y = left.y+(v/2)-(r*math.cos(theta))
        else:
            y = left.y+(v/2)+(r*math.cos(theta))
    else:
        theta = math.asin(v/(2*dist))
        x = left.x-(dist*math.cos(theta))
        y = left.y + (v/2)
    return Point(x,y)

class Vis:
    def __init__(self):
        self.frame = Frame(root)
        self.canvas = Canvas(self.frame,bg="white",width=width,height=height)
        self.canvas.pack()
        self.frame.pack()
        self.run()
    def run(self):
        self.count_calc0 = 0
        self.count_calc1 = 0
        self.count_calc2 = 0
        self.count_calc3 = 0
        self.count_calc4 = 0
        self.count_calc5 = 0
        self.prev_x = 0
        self.best = -1
        self.best_centre = []
        for self.sweep in xrange(0,len(points)):
            self.count_calc0 += 1
            if len(points[self.sweep].right) <= self.best:
                break
            self.calc(points[self.sweep])
        self.sweep = len(points) # so that draw() stops highlighting it
        print "BEST",self.best+1, self.best_centre # count left-most point too
        print "counts",self.count_calc0, self.count_calc1,self.count_calc2,self.count_calc3,self.count_calc4,self.count_calc5
        self.draw()
    def calc(self,p):
        for self.right in p.right:
            self.count_calc1 += 1
            if (self.right.left + len(self.right.right)) < self.best:
                # this can never help us
                continue
            self.count_calc2 += 1
            self.centre = equidist(p,self.right,radius)
            assert abs(self.centre.distance(p)-self.centre.distance(self.right)) < 1
            count = 0
            for p2 in p.right:
                self.count_calc3 += 1
                if self.centre.distance(p2) <= radius:
                    count += 1
            if self.best < count:
                self.count_calc4 += 4
                self.best = count
                self.best_centre = [self.centre]
            elif self.best == count:
                self.count_calc5 += 5
                self.best_centre.append(self.centre)
            self.draw()
            self.frame.update()
            time.sleep(0.1)
    def draw(self):
        self.canvas.delete(ALL)
        # draw best circle
        for best in self.best_centre:
            self.canvas.create_oval(best.x-radius,best.y-radius,\
                best.x+radius+1,best.y+radius+1,fill="red",\
                outline="red")
        # draw current circle
        if self.sweep < len(points):
            self.canvas.create_oval(self.centre.x-radius,self.centre.y-radius,\
                self.centre.x+radius+1,self.centre.y+radius+1,fill="pink",\
                outline="pink")
        # draw all the connections
        for p in points:
            for p2 in p.right:
                self.canvas.create_line(p.x,p.y,p2.x,p2.y,fill="lightGray")
        # plot visited points
        for i in xrange(0,self.sweep):
            p = points[i]
            self.canvas.create_line(p.x-2,p.y,p.x+3,p.y,fill="blue")
            self.canvas.create_line(p.x,p.y-2,p.x,p.y+3,fill="blue")
        # plot current point
        if self.sweep < len(points):
            p = points[self.sweep]
            self.canvas.create_line(p.x-2,p.y,p.x+3,p.y,fill="red")
            self.canvas.create_line(p.x,p.y-2,p.x,p.y+3,fill="red")
            self.canvas.create_line(p.x,p.y,self.right.x,self.right.y,fill="red")
            self.canvas.create_line(p.x,p.y,self.centre.x,self.centre.y,fill="cyan")
            self.canvas.create_line(self.right.x,self.right.y,self.centre.x,self.centre.y,fill="cyan")
        # plot unvisited points
        for i in xrange(self.sweep+1,len(points)):
            p = points[i]
            self.canvas.create_line(p.x-2,p.y,p.x+3,p.y,fill="green")
            self.canvas.create_line(p.x,p.y-2,p.x,p.y+3,fill="green")

radius = 60
diameter = radius*2
width = 800
height = 600

points = []

# make some points
for i in xrange(0,100):
    points.append(Point(random.randrange(width),random.randrange(height)))

# sort points for find-the-right sweep
points.sort(lambda a, b: int(a.x)-int(b.x))

# work out those points to the right of each point
for i in xrange(0,len(points)):
    p = points[i]
    for j in xrange(i+1,len(points)):
        p2 = points[j]
        if p2.x > (p.x+diameter):
            break
        if (abs(p.y-p2.y) <= diameter) and \
            p.distance(p2) < diameter:
            p.right.append(p2)
            p2.left += 1

# sort points in potential order for sweep, point with most right first
points.sort(lambda a, b: len(b.right)-len(a.right))

# debug
for p in points:
    print p, p.left, p.right

# show it
root = Tk()
vis = Vis()
root.mainloop()
2
ответ дан 3 December 2019 в 10:44
поделиться

Очень быстрая идея, не обязательно правильная:

  • для каждой точки p вы рассчитываете «зону покрытия кандидата» - континуум точек, где может быть центр круга его покрытия. Естественно, это также круг диаметра D с центром в P.
  • для каждой точки P. Вы пересекаете свою область покрытия кандидата с соответствующими областями других точек. Некоторые из зон охватывающих кандидатов могут пересекать с P имеющимися друг с другом. Для каждого пересечения вы считаете количество пересеченных районов. Фигура, которая пересекается большинством кандидатских областей, является областью кандидата для центра охватывающего круга, который охватывает P и как можно больше других моментов.
  • Найти область кандидата с наибольшим количеством пересечений

, кажется, как сложность N ^ 2, при условии, что расчетные пересечения районов окружности в форме простых

2
ответ дан 3 December 2019 в 10:44
поделиться

Если я не пропустил что-то очевидное, думаю, есть простой ответ.

Для прямоугольной области MxN, количество точек P, радиус R:

  • Инициализируйте карту (например, 2D массив int) области MxN до всех нулей
  • Для каждой из точек P
    • увеличьте все точки карты в радиусе R на 1
  • Найдите элемент карты с максимальным значением - это будет центр искомой окружности

Это O(P), предполагая, что P является переменной, представляющей интерес.

4
ответ дан 3 December 2019 в 10:44
поделиться

Похоже, это может быть то, за чем вы охотитесь: http://developer.apple.com/mac/library/samplecode/AppleJavaExtensions/

Это съемная банка классов заглушек, представляющая новую Apple API eAWT и eIO для Java 1.4 в Mac OS X. Назначение этих заглушек позволяет компилировать код eAWT- или eIO-ссылки на Платформы, отличные от Mac OS X.

-121--2954022-

Есть, по крайней мере, два мира, о которых я знаю:

http://drupal.org/project/popups_reference , который использует http://drupal.org/project/popups

и

http://drupal.org/project/noderelationships , который использует http://drupal.org/project/modalframe

Оба из них о создании Они могут быть для более общих целей, или вы, вероятно, могли бы адаптировать один из них. В последнее время я наслаждаюсь нодерелайнациями. Недавно не пробовал другой.

-121--3383574-

Как использовать алгоритм кластеризации для идентификации кластера точек. Затем определите кластер с максимальным количеством точек. Возьмите среднюю точку кластера с максимальными точками в качестве центра окружности, а затем нарисуйте окружность.

MATLAB поддерживает реализацию алгоритма k-means и возвращает 2-d массив (матрица, если быть точной) кластерных средств и соответствующих кластерных идентификаторов.

Одна хорошо известная оборотная сторона k-средства принимает решение о k (количестве кластеров) перед рукой. Это можно разрешить, хотя - можно узнать значение k из точек данных. Проверьте документ .

Надеюсь, это поможет.

ура

0
ответ дан 3 December 2019 в 10:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: