Подготовка к школе
1 класс
2 класс
3 класс
4 класс
5 класс
6 класс
7 класс
8 класс
9 класс
10 класс
11 класс
ОГЭ
ЕГЭ
Для всех
Назад

27. Программирование: #299520

Сообщить о проблеме
Задание #299520
Задание было решено верно
Задание было решено неверно

Фрагмент звёздного неба спроецирован на плоскость с декартовой системой координат. Учёный решил провести кластеризацию полученных точек, являющихся изображениями звёзд, то есть разбить их множество на $N$ непересекающихся непустых подмножеств (кластеров), таких, что точки каждого подмножества лежат внутри квадрата со стороной длиной $H$, причём эти квадраты между собой не пересекаются. Стороны квадрата не обязательно параллельны координатным осям. Гарантируется, что такое разбиение существует и единственно для заданных размеров квадрата.

Будем называть центром кластера точку этого кластера, сумма расстояний от которой до всех остальных точек кластера минимальна. Для каждого кластера гарантируется единственность его центра. Расстояние между двумя точками на плоскости $A(x_1, y_1)$ и $B(x_2, y_2)$ вычисляется по формуле $$d(A, B) = \sqrt{(x_2 — x_1)^2 + (y_2 — y_1)^2}.$$

В файле $А$ хранятся координаты точек двух кластеров, где $H = 4{,}7$ для каждого кластера. В каждой строке записана информация о расположении на карте одной звезды: сначала координата $x$, затем координата $y$. Известно, что количество точек не превышает $1000$.

В файле $Б$ хранятся координаты точек трёх кластеров, где $H = 4$ для каждого кластера. Известно, что количество точек не превышает $10,000$. Структура хранения информации в файле $Б$ аналогична файлу $А$.

Для каждого файла определите координаты центра каждого кластера, затем вычислите два числа: $P_x$ — среднее арифметическое абсцисс центров кластеров и $P_y$ — среднее арифметическое ординат центров кластеров.

В ответе запишите четыре числа через запятую: сначала целую часть произведения $|P_x| \times 10,000$, затем целую часть произведения $|P_y| \times 10,000$ для файла $А$, далее — аналогичные данные для файла $Б$.

Возможные данные одного из файлов иллюстрированы графиком. Внимание! График приведён в иллюстративных целях для произвольных значений, не имеющих отношения к заданию. Для выполнения задания используйте данные из прилагаемого файла.

Центр определяется через сумму расстояний — это точка самого кластера, ищем её перебором, а не как среднее арифметическое координат. А вот $P_x$ и $P_y$ — уже обычные средние арифметические, но не по всем точкам, а только по найденным центрам.

Кластеризация. Квадраты не пересекаются, поэтому кластеры разделены в пространстве. Разбиваем точки на компоненты связности. Порог $0{,}3$ здесь мал — данные разрежены, и файлы рассыпаются на полтора десятка обрывков; начиная с $0{,}5$–$0{,}8$ результат устойчив вплоть до $2{,}0$. Берём $0{,}8$.

Проверяем допустимость: в файле $А$ группы занимают области примерно $3{,}2 \times 2{,}5$ и $3{,}5 \times 2{,}5$ — обе умещаются в квадрат со стороной $4{,}7$. В файле $Б$ области около $1{,}8 \times 1{,}6$, $2{,}5 \times 2{,}8$ и $0{,}7 \times 1{,}9$ при допустимой стороне $4$. Число кластеров совпадает с условием: два и три.

import zipfile, math
from xml.etree import ElementTree as ET

T = '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}'
O = '{urn:oasis:names:tc:opendocument:xmlns:office:1.0}'

def load(name):
    x = ET.fromstring(zipfile.ZipFile(name).read('content.xml'))
    P = []
    for r in x.iter(T + 'table-row'):
        parts = []
        for c in r.iter(T + 'table-cell'):
            v = c.get(O + 'value') or ''.join(c.itertext()).strip()
            if v: parts.append(v)
        tok = ' '.join(parts).replace(',', '.').split()
        if len(tok) < 2: continue
        try: P.append((float(tok[0]), float(tok[1])))
        except ValueError: pass
    return P

def center(c):
    return min(c, key=lambda a: sum(math.dist(a, b) for b in c))

def clusters(pts, eps=0.8):
    unused, res = set(range(len(pts))), []
    while unused:
        i = unused.pop(); comp, stack = [i], [i]
        while stack:
            a = stack.pop()
            for j in list(unused):
                if math.dist(pts[a], pts[j]) < eps:
                    unused.discard(j); comp.append(j); stack.append(j)
        res.append([pts[k] for k in comp])
    return res

for name in ['27-29А.ods', '27-29Б.ods']:
    cs = [center(c) for c in clusters(load(name))]
    Px = sum(p[0] for p in cs) / len(cs)
    Py = sum(p[1] for p in cs) / len(cs)
    print(int(abs(Px) * 10000), int(abs(Py) * 10000))

Результаты для файла $А$. Всего $220$ точек, два кластера ровно по $110$ точек. Первый занимает область $x \in [4{,}27;\ 7{,}44]$, $y \in [23{,}07;\ 25{,}60]$, его центр — $(6{,}110722;\ 24{,}26957)$; второй занимает $x \in [2{,}23;\ 5{,}73]$, $y \in [4{,}69;\ 7{,}17]$ с центром $(3{,}830122;\ 5{,}815582)$. Отсюда $P_x = (6{,}110722 + 3{,}830122) / 2 = 4{,}970422$ и $P_y = (24{,}26957 + 5{,}815582) / 2 = 15{,}042576$, что после умножения на $10,000$ и отбрасывания дробной части даёт $49704$ и $150425$.

Результаты для файла $Б$. Всего $510$ точек, три кластера по $298$, $106$ и $106$ точек с центрами $(-1{,}66068;\ -4{,}56708)$, $(-8{,}18279;\ 3{,}849255)$ и $(-1{,}75482;\ 6{,}741675)$. Отсюда $P_x = -3{,}866096667$ и $P_y = 2{,}00795$, что даёт $38660$ и $20079$.

Показать
Очки опыта 20
Спросить Зави
0 заданий сегодня

Предложить улучшение