Задание 27
Анализ данных
Точки и расстояния, чтение файла, разделение на кластеры по границам и признакам, центр перебором кандидатов и ответ по центрам и расстояниям.
6 подтем · 33 задачи + 9 дополнительных · высокий · ≈ 36 мин
Подтема 1 из 6
Точки, расстояния и файл
Что спрашивают в задании 27, точка и кластер в Python, расстояние, чтение файла с характеристиками, строка частицы и полярные координаты.
Как устроена тема
В задании 27 дают файл с сотнями точек — звёзд, частиц, измерений — и просят разбить их на группы, найти в каждой группе центр и собрать из центров и расстояний ответ. Вот задача, которую мы решим в этой теме:
«Входной файл 27-4.txt содержит сведения о частицах, зарегистрированных детектором. В каждой строке записаны координаты частицы x и y, проекции её скорости vx и vy, масса m и признак частицы — римское число от I до VII; значения разделены табуляцией. Кинетическая энергия частицы E = m · (vx² + vy²) / 2. Частицы образуют четыре кластера: модуль разности энергий любых двух частиц одного кластера не превышает 2. Центром кластера назовём частицу, для которой сумма модулей разностей её энергии и энергий остальных частиц кластера минимальна. Найдите Q₁ — наибольшее расстояние между двумя частицами одного кластера с признаком II и Q₂ — наибольшую кинетическую энергию центра кластера. В ответе запишите целые части произведений Q₁ · 10 000 и Q₂ · 10 000.»
Любое задание 27 решается в четыре шага: прочитать записи файла, разделить их на кластеры, найти центры по определению из условия и собрать ответ. Каждому шагу посвящена своя подтема. Разберём, что значат слова условия:
| В условии | Что это значит |
|---|---|
| точка, звезда, частица | одна строка файла: координаты x и y и, может быть, характеристики |
| расстояние d(A, B) = √((x₂ − x₁)² + (y₂ − y₁)²) | обычная длина отрезка: в Python — dist(a, b) |
| кластер, точки лежат внутри квадратов | группы видны на рисунке, их разделяют границами |
| модуль разности энергий не превышает 2 | группы делят по вычисленной величине, а не по координатам |
| аномалии | точки вне всех кластеров: их откладывают отдельно |
| центр — точка, сумма расстояний от которой до остальных минимальна | одна из точек кластера: проверяют каждую как кандидата |
| целая часть произведения на 10 000 | int(value * 10000) — дробную часть отбрасывают |
Начнём с точек, расстояния и чтения файла — без них не обходится ни одна задача. Тема состоит из пяти подтем и дополнительного урока — у каждой своя страница:
- Точки, расстояния и файл — ты сейчас здесь: точка, расстояние, чтение строк с характеристиками.
- Разделение на кластеры — рисунок, границы, аномалии, деление по энергии.
- Центр кластера — перебор кандидатов и своя формула расстояния.
- Ответ по центрам — средние, наибольший и наименьший кластер, целая часть.
- Расстояния и пары точек — радиус, диаметр, пары одного вида; решим задачу темы.
- Соседи, другие центры и статистика — дополнительный урок для редких задач.
Точка и кластер
Что записано в строке файла и как хранить это в программе?
Строка файла — одна точка: пара чисел x и y. В Python точку хранят кортежем, кластер — списком точек, все кластеры — списком списков. Сюжет бывает любой — звёзды, частицы, деревья, — а программа видит пары чисел:
1.5 3.22.1 4.87.3 1.4Координата x — положение по горизонтали, y — по вертикали. A = (2; 5) — на 2 единицы правее начала координат и на 5 выше. Отрицательная координата задаёт противоположное направление: B = (−3; 4) — на 3 левее и на 4 выше. В условиях x называют абсциссой, y — ординатой.
Упорядоченная пара (2.0, 5.0) в Python — : элемент point[0] — координата x, point[1] — координата y. Точки собирают в , а кластеры — в список списков:
point = (2.0, 5.0)x, y = pointprint(point[0], y) clusters = [ [(0, 0), (1, 1), (2, 0)], [(10, 8), (11, 9)]]clusters[1].append((12, 8)) print(len(clusters)) # сколько кластеровprint(len(clusters[1])) # сколько точек во второмfor x, y in clusters[1]: print(x, y)x, y = point раскладывает пару по двум переменным, append добавляет точку в конец списка, а цикл for x, y in … перебирает точки сразу с координатами. Не путай два количества: len(clusters) — сколько групп, len(clusters[1]) — сколько точек в группе.
Расстояние
Как найти расстояние между двумя точками, зная их координаты?
Разности координат — катеты прямоугольного треугольника, а расстояние — его гипотенуза: d(A, B) = √((x₂ − x₁)² + (y₂ − y₁)²). Для A = (1; 2) и B = (4; 6) по горизонтали точки отличаются на 4 − 1 = 3, по вертикали — на 6 − 2 = 4:
Такое расстояние называют евклидовым — это обычная длина отрезка. Формулу можно записать самому: ** 2 — квадрат, ** 0.5 — корень. Но в модуле math уже есть функция dist, ею и будем пользоваться:
from math import dist a, b = (1, 2), (4, 6)dx, dy = b[0] - a[0], b[1] - a[1]print((dx ** 2 + dy ** 2) ** 0.5)print(dist(a, b))print(int(dist((0, 0), (1, 1)) * 10000))Последняя строка — формат ответа задания 27: значение умножают на 10 000 и отбрасывают дробную часть. √2 ≈ 1,41421356, а ответ — 14142. Это делает , а не round: подробнее — в подтеме 4.
Пригодятся три свойства: d(A, B) = d(B, A), d(A, A) = 0 и d(A, B) ≥ 0.
Сравнение с порогом
Нужно ли извлекать корень, чтобы проверить, что точки ближе заданного расстояния?
Нет: при r ≥ 0 условие d(A, B) ≤ r равносильно (x₂ − x₁)² + (y₂ − y₁)² ≤ r², и корень не нужен.
a, b, r = (1, 2), (4, 6), 5 dx = a[0] - b[0]dy = a[1] - b[1] if dx * dx + dy * dy <= r * r: print("Точки достаточно близки")Почему это допустимо? Для неотрицательных чисел возведение в квадрат сохраняет порядок: если одно расстояние меньше другого, его квадрат тоже меньше. Здесь 25 ≤ 25 — ровно потому, что 5 ≤ 5.
Но заменять сумму расстояний суммой их квадратов нельзя. Это уже другая величина. В подтеме о центре кластера разберём конкретный пример, где из-за такой замены выбирается другая точка.
Чтение файла
Как прочитать точки из файла и ни одной не потерять?
Сначала посмотри на первые строки файла, потом разбирай каждую строку в три действия: заменить запятые точками, разделить, превратить части в числа. Форматы бывают разные — выбери, чтобы увидеть, что с ним делать:
- числа через пробел
1.25 3.70читаем как есть- запятая в дробях
1,25 3,70заменить запятые точками- заголовок
X Yпропустить первую строку- табуляция
1,25→3,70→K3Vsplit() делит и по табуляции
Метод меняет запятые на точки, без аргументов делит строку по пробелам и табуляциям, сколько бы их ни было подряд, а превращает текст в дробное число:
line = "1,25 3,70"parts = line.replace(",", ".").split()print(parts)print(float(parts[0]) + float(parts[1]))Функция чтения делает это для каждой строки. Координаты берём из первых двух частей — так она подойдёт и для файлов, где после координат записано что-то ещё:
def read_points(filename, has_header=False): points = [] with open(filename, encoding="utf-8-sig") as f: if has_header: f.readline() for line in f: if not line.strip(): continue parts = line.replace(",", ".").split() points.append((float(parts[0]), float(parts[1]))) return points points = read_points("example27.txt", has_header=True)print(len(points), points[:3])- открывает файл и сам закрывает его после блока;
for line in fперебирает строки. f.readline()читает одну строку — так пропускаем заголовок, еслиhas_headerистинно. По умолчанию заголовка нет.if not line.strip(): continueпропускает пустые строки — обычно пустую последнюю.points[:3]— , первые три точки. После чтения всегда выводи количество и первые точки.
Заголовок:пропустить лишнее опаснее, чем забыть
Если заголовок не пропустить, программа сразу остановится: ValueError: could not convert string to float: 'X'. Это хотя бы заметно. Обратная ошибка тише: в файле 27-1.txt заголовка нет, и пропуск первой строки «на всякий случай» молча теряет точку:
print(len(read_points("27-1.txt")))print(len(read_points("27-1.txt", has_header=True)))И ещё: латинская A и кириллическая А в имени файла выглядят одинаково, но для компьютера это разные символы.
Код звезды
Как прочитать строку, где после координат записан код звезды?
Код хранят в той же записи, что и координаты, а разбирают по позициям символов. В задачах ЕГЭ-2026 у каждой звезды записан код вроде K3V слитно: латинская буква — спектральный класс (цвет), цифра — подкласс, римское число — класс светимости. Так устроен и наш файл 27-3.txt:
4,387365 8,408613 A0III1,932849 1,048969 K3V3,921424 2,369304 VIIБуква задаёт цвет, римское число — размер звезды. Таблицы соответствия даны в условии; выбери обозначение, чтобы увидеть, что оно значит:
- O
- голубая
- B
- бело-голубая
- A
- белая
- F
- жёлто-белая
- G
- жёлтая
- K
- оранжевая
- M
- красная
- I
- сверхгигант
- II
- яркий гигант
- III
- гигант
- IV
- субгигант
- V
- карлик
- VI
- субкарлик
- VII
- белый карлик
«Красный гигант» в условии буквально переводится в две проверки: класс M и светимость III.
Обрати внимание на третью строку: у белых карликов в файле записан только класс светимости VII, без буквы и цифры. Поэтому code[0] не всегда спектральный класс.
Сначала проверяем, буква ли это, и только потом разбираем код по позициям. Запусти функцию по шагам и посмотри, какую ветвь проходит каждый код:
def parse_kind(code): if code[0] in "OBAFGKM": return code[0], code[1], code[2:] return "", "", code print(parse_kind("M4III"))print(parse_kind("VII"))Для M4III выполняется строка 3: буква, цифра и всё остальное — срез code[2:]. Для VII проверка в строке 2 ложна, и функция возвращает пустой класс. Записи файла читаем так же, как точки, только сохраняем ещё и код:
def read_stars(filename): stars = [] with open(filename, encoding="utf-8-sig") as f: for line in f: parts = line.replace(",", ".").split() x, y = float(parts[0]), float(parts[1]) stars.append((x, y, parts[2])) return starsstars = read_stars("27-3.txt")print(len(stars))print(stars[:2])Для расстояния берут только координаты — срез s[:2], первые два элемента записи: dist(s[:2], t[:2]). Код в расчёт не идёт, по нему только отбирают звёзды нужного вида.
Строка частицы
Как прочитать строку частицы из задачи темы?
Строка частицы — шесть частей: пять чисел и признак. Кластер здесь определяют не координаты, а энергия, вычисленная по скорости и массе. В файле 27-4.txt записаны координаты x и y, проекции скорости vx и vy, масса m и признак — римское число. Значения разделены табуляцией, дробная часть — запятой. split() справляется и с табуляцией:
def read_particles(filename): particles = [] with open(filename, encoding="utf-8-sig") as f: for line in f: parts = line.replace(",", ".").split() x, y, vx, vy, m = [float(v) for v in parts[:5]] particles.append((x, y, vx, vy, m, parts[5])) return particlesПервые пять частей становятся числами и раскладываются по именам, признак остаётся строкой. В записи частицы p номер части — номер элемента кортежа:
Кинетическая энергия частицы массы m со скоростью (vx; vy) — E = m · (vx² + vy²) / 2. Например, для массы 0,8 и скорости (2; −1,5): E = 0,8 · (4 + 2,25) / 2 = 2,5. Запишем формулу функцией и проверим её на этом примере и на первой частице файла:
def energy(p): vx, vy, m = p[2], p[3], p[4] return m * (vx ** 2 + vy ** 2) / 2print(energy((1.25, -3.4, 2.0, -1.5, 0.8, "III"))) particles = read_particles("27-4.txt")print(len(particles))print(particles[0], energy(particles[0]))У первой частицы файла энергия около 6,07. По энергиям частицы и разделим на кластеры в подтеме 2.
Полярные координаты
Что делать, если в строке файла записаны не x и y, а угол и расстояние до начала координат?
Это полярные координаты: угол φ и радиус r. До всех расчётов их переводят в обычные: x = r · cos φ, y = r · sin φ. Угол отсчитывают от положительного направления оси x против часовой стрелки, радиус — расстояние от начала координат до точки:
Функции cos и sin из модуля math ждут угол в радианах, а в файле он в градусах. Переводит radians; без неё cos(60) считает косинус 60 радиан:
from math import cos, sin, radians def polar_to_xy(phi, r): a = radians(phi) return r * cos(a), r * sin(a) x, y = polar_to_xy(60, 4)print(round(x, 3), round(y, 3))print(round(cos(60), 3), round(cos(radians(60)), 3)) def read_polar(filename): points = [] with open(filename, encoding="utf-8-sig") as f: for line in f: parts = line.replace(",", ".").split() phi, r = float(parts[0]), float(parts[1]) points.append(polar_to_xy(phi, r)) return points points = read_polar("27-7.txt")print(len(points), [round(v, 3) for v in points[0]])В файле 27-7.txt первая строка — 25,581 6,386: угол 25,581°, радиус 6,386. После перевода это точка (5,76; 2,757), и дальше с ней работают как с любой другой: расстояния считают по x и y.
Итого
- Точка и кластеркортеж
(x, y), список точек, список списков - Расстояние
dist(a, b); с порогом сравнивают квадраты - Ответ
int(value * 10000)— целая часть - Чтение
replace(",", "."),split(),float; заголовок — только если он есть - Характеристикирядом с координатами; код звезды — сначала проверь букву
- Частица и полярныеE = m · (vx² + vy²) / 2; x = r · cos φ, y = r · sin φ
Проверьте себя
Ответь сначала сам, потом открой ответ.
(3, 4), (-4, 2), (1, -5) ближе всех к началу координат? Чему равно это расстояние?ОтветСкрыть ответ
(-4, 2): квадраты расстояний 25, 20 и 26, расстояние √20 ≈ 4,472.(4, 7) и (1, 3). Верно ли, что расстояние между ними не больше 5? А что оно меньше 5? Проверь без извлечения корня.ОтветСкрыть ответ
"-2,5\t4,75".split(" ") и "-2,5 4,75".replace(",", ".").split()?ОтветСкрыть ответ
['-2,5\t4,75']: по пробелу строку с табуляцией не разделить. Второе — ['-2.5', '4.75']: split() делит по любым пробельным символам, сколько бы их ни было подряд.K7V, VII и A0III: спектральный класс, цвет и класс светимости.ОтветСкрыть ответ
K7V — класс K (оранжевая), светимость V (карлик); VII — белый карлик без спектрального класса; A0III — класс A (белая), светимость III (гигант).90 5 и 180 2. Какие это точки на обычной плоскости?ОтветСкрыть ответ
radians(phi).Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Кластеры как список списков
Дано clusters = [[(0, 0), (1, 1)], [(5, 5), (6, 5), (7, 6)], [(10, 0)]]. Чему равны len(clusters), len(clusters[1]) и clusters[1][2][0]?
Введите три числа через пробел в том порядке, в каком их спрашивают.
Подсказка
Индексы начинаются с нуля: clusters[1] — второй кластер.
Решение
3, 3 и 7: три кластера, во втором три точки, его третья точка (7, 6) имеет абсциссу 7.
Решение программой
clusters = [[(0, 0), (1, 1)], [(5, 5), (6, 5), (7, 6)], [(10, 0)]]print(len(clusters), len(clusters[1]), clusters[1][2][0])Ответ: 3 3 7
Расстояние 3–4–5
Найди евклидово расстояние между (2, 1) и (5, 5).
Введите число.
Подсказка
Разности координат — катеты прямоугольного треугольника.
Решение
5: разности координат равны 3 и 4.
Решение программой
from math import dist print(f'{dist((2, 1), (5, 5)):g}')Ответ: 5
Расстояние с отрицательными координатами
Найди расстояние между (-1, -2) и (5, 6).
Введите число.
Подсказка
Разность 5 − (−1) равна 6.
Решение
10: разности координат 6 и 8, √(36 + 64) = 10.
Решение программой
from math import dist print(f'{dist((-1, -2), (5, 6)):g}')Ответ: 10
Расстояние в формате ответа
Найди расстояние между точками A (−1,5; 2,25) и B (3,1; −0,4). В ответе запиши целую часть произведения найденного расстояния на 10 000.
Введите число.
Подсказка
Умножь расстояние на 10 000 и отбрось дробную часть.
Решение
53087: разности координат 4,6 и −2,65, расстояние √(21,16 + 7,0225) ≈ 5,30872.
Решение программой
from math import dist print(int(dist((-1.5, 2.25), (3.1, -0.4)) * 10000))Ответ: 53087
Звёзды и белые карлики
Введите два числа через пробел: количество звёзд и количество белых карликов.
Подсказка
Код белого карлика — ровно VII, без спектрального класса.
Решение
601 звезда, из них 70 белых карликов.
Решение программой
codes = []with open('27-3.txt', encoding='utf-8-sig') as f: for line in f: codes.append(line.split()[2])print(len(codes), codes.count('VII'))Ответ: 601 70
Красные гиганты
Введите число.
Подсказка
Класс — первый символ кода, светимость — всё после подкласса.
Решение
37 красных гигантов.
Решение программой
count = 0with open('27-3.txt', encoding='utf-8-sig') as f: for line in f: code = line.split()[2] if code[0] == 'M' and code[2:] == 'III': count += 1print(count)Ответ: 37
Кинетическая энергия
Найди кинетическую энергию частицы массы 2 со скоростью (−1; 3).
Введите число.
Подсказка
E = m · (vx² + vy²) / 2.
Решение
10: 2 · (1 + 9) / 2.
Решение программой
m, vx, vy = 2, -1, 3print(f'{m * (vx ** 2 + vy ** 2) / 2:g}')Ответ: 10
Наибольшая энергия частицы
В файле 27-4.txt записаны частицы: координаты x и y, проекции скорости vx и vy, масса m и признак. Найди наибольшую кинетическую энергию частицы файла. В ответе запиши целую часть произведения найденной энергии на 10 000.
Введите число.
Подсказка
Скорость — третий и четвёртый столбцы, масса — пятый.
Решение
133402: наибольшая энергия ≈ 13,34021.
Решение программой
best = 0with open('27-4.txt', encoding='utf-8-sig') as f: for line in f: p = line.replace(',', '.').split() vx, vy, m = float(p[2]), float(p[3]), float(p[4]) best = max(best, m * (vx ** 2 + vy ** 2) / 2)print(int(best * 10000))Ответ: 133402
Полярные координаты звёзд
В файле 27-7.txt записаны звёзды в полярных координатах: в каждой строке — полярный угол φ в градусах и полярный радиус r. Переведи все точки в обычные координаты x = r · cos φ, y = r · sin φ и найди наибольшую абсциссу и наибольшую ординату. В ответе запиши целые части произведений этих чисел на 10 000.
Введите два числа через пробел в том порядке, в каком их спрашивают.
Подсказка
Функции cos и sin ждут радианы: сначала radians(phi).
Решение
Перевод каждой строки — x = r · cos φ, y = r · sin φ после radians.
Решение программой
from math import cos, sin, radians xs, ys = [], []with open('27-7.txt') as f: for line in f: phi, r = map(float, line.replace(',', '.').split()) xs.append(r * cos(radians(phi))) ys.append(r * sin(radians(phi)))print(int(max(xs) * 10000), int(max(ys) * 10000))Ответ: 85940 57203