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

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

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

Фрагмент звёздного неба спроецирован на плоскость с декартовой системой координат. Учёный решил провести кластеризацию полученных точек, являющихся изображениями звёзд, то есть разбить их множество на $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 = 6$, $W = 6$ для каждого кластера. В каждой строке записана информация о расположении на карте одной звезды: сначала координата $x$, затем координата $y$. Известно, что количество точек не превышает $1000$.

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

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

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

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

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

Кластеризация. Квадраты не пересекаются, поэтому кластеры разделены в пространстве. Разбиваем точки на компоненты связности, но порог здесь нужно подбирать особенно внимательно, потому что файл $А$ очень разрежен: в нём всего $99$ точек, разбросанных по областям размером около $5 \times 5$. При пороге $1{,}0$ он рассыпается на семь кусков, и только начиная с $2{,}0$ остаются ровно две группы — $50$ и $49$ точек. В файле $Б$ точек много ($9916$), там сгустки плотные и результат устойчив начиная с $1{,}0$: три группы по $3313$, $3306$ и $3297$ точек.

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

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):
    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, eps in [('27-24_A.ods', 2.0), ('27-24_B.ods', 1.0)]:
    cs = [center(c) for c in clusters(load(name), eps)]
    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))

Результаты для файла $А$. Всего $99$ точек, два кластера по $50$ и $49$ точек. Первый занимает область $x \in [1{,}05;\ 6{,}33]$, $y \in [-5{,}09;\ -0{,}33]$, его центр — $(3{,}981033369;\ -1{,}961127579)$; второй занимает $x \in [-2{,}04;\ 2{,}71]$, $y \in [5{,}00;\ 10{,}64]$ с центром $(1{,}262277635;\ 6{,}797635538)$. Отсюда $P_x = 2{,}621655502$ и $P_y = 2{,}418253979$, что после умножения на $10,000$ и отбрасывания дробной части даёт $26216$ и $24182$.

Результаты для файла $Б$. Всего $9916$ точек, три кластера по $3313$, $3306$ и $3297$ точек с центрами $(25{,}20349762;\ -0{,}833550091)$, $(4{,}309073189;\ 6{,}615238685)$ и $(15{,}75501912;\ 13{,}34466476)$. Отсюда $P_x = 15{,}089196643$ и $P_y = 6{,}375451118$, что даёт $150891$ и $63754$.

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

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