Подтема 6 из 6 · дополнительный урок
Вся таблица и соседние ячейки
Условия на столбец, всю таблицу или соседние ячейки — два прохода и перебор соседей.
Где считаем
Дополнительный урок — для продвинутых. В нём редкие задачи, где условие на ячейку зависит от её столбца, всей таблицы или соседних ячеек; на экзаменах такие задачи не встречались. Задачи основных подтем решаются без него.
Ячейка «интересная», если её число встречается в своей строке один раз, а в других строках таблицы — 160 раз. Как посчитать «в других строках»?
Сначала определяют область подсчёта: своя строка, свой столбец, вся таблица, другие ячейки или другие строки.
Пусть данные занимают A1:F5000. Выбери, где считаем значение A1:
- в своей строке
=СЧЁТЕСЛИ($A1:$F1;A1) - в своём столбце
=СЧЁТЕСЛИ(A$1:A$5000;A1) - во всей таблице
=СЧЁТЕСЛИ($A$1:$F$5000;A1) - в других ячейках столбца
=СЧЁТЕСЛИ(A$1:A$5000;A1)-1 - в других строках
=СЧЁТЕСЛИ($A$1:$F$5000;A1)-СЧЁТЕСЛИ($A1:$F1; A1)
Знак $ из закрепляет границы области при копировании. Подсчёт всегда включает саму ячейку: для «других ячеек столбца» вычитают 1, а для «других строк» — все появления в своей строке. Если число встречается в таблице 17 раз, а в своей строке 3, в других строках оно встречается 14 раз, а не 16.
Появления и строки — разные величины: если 5 встречается в первой строке трижды, а во второй дважды, появлений пять, а строк с пятёркой — две.
Ячейка и строка
Условие на ячейку проверяют в два уровня: сначала отмечают подходящие ячейки, затем по их отметкам — строки. Пусть ячейка подходит, если её число встречается в своей строке один раз и ещё хотя бы раз — в других ячейках своего столбца. Для A1 таблицы из четырёх строк по три числа отметка в D1:
=ЕСЛИ(И(СЧЁТЕСЛИ($A1:$C1; A1)=1;СЧЁТЕСЛИ(A$1:A$4; A1)-1>=1); 1; 0)Формулу копируют вправо до F1 и вниз. Строка с хотя бы одной подходящей ячейкой получает отметку =ЕСЛИ(СУММ(D1:F1)>=1;, и только эти отметки складывают:
| A | B | C | D | E | F | G | |
|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 2 | 0 | 0 | 0 | 0 |
| 2 | 4 | 2 | 5 | 0 | 1 | 0 | 1 |
| 3 | 2 | 6 | 7 | 1 | 0 | 0 | 1 |
| 4 | 8 | 2 | 2 | 0 | 0 | 0 | 0 |
| 5 | 2 |
D1скопирована до F4=ЕСЛИ(И(СЧЁТЕСЛИ($A1:$C1;A1)=1;СЧЁТЕСЛИ(A$1:A$4; A1)-1>=1); 1; 0) G1скопирована до G4=ЕСЛИ(СУММ(D1:F1)>=1;1; 0) G5=СУММ(G1:G4)
Подходят вторая строка (двойка единственна в строке, и в столбце B есть ещё двойка) и третья (двойка в столбце A). Тройка первой строки единственна в строке, но в своём столбце больше не встречается. Сумма отметок всех ячеек дала бы число ячеек, а не строк.
Два прохода
Когда условие зависит от всего столбца или всей таблицы, программа сначала читает все данные, а потом проходит по ним второй раз. При чтении первой строки ещё неизвестно, сколько раз её числа встретятся ниже. Таблицу собирают в список строк:
table = []with open("9.txt") as f: for line in f: a = [int(part) for part in line.split()] table.append(a)print(len(table), table[0])Первый проход считает частоты каждого столбца, второй проверяет ячейки и строки. column_counts[j] — столбца j, перебор строк и столбцов — :
from collections import Counter table = [ [2, 3, 2], [4, 2, 5], [2, 6, 7], [8, 2, 2],]width = len(table[0]) column_counts = []for j in range(width): column_counts.append(Counter()) for a in table: for j in range(width): column_counts[j][a[j]] += 1 answer = 0for a in table: row_counts = Counter(a) good_cells = 0 for j in range(width): x = a[j] if ( row_counts[x] == 1 and column_counts[j][x] - 1 >= 1 ): good_cells += 1 if good_cells >= 1: answer += 1 print(answer)Ответ тот же, что на листе «Ячейки». У Counter частота ещё не встречавшегося числа равна нулю, поэтому её можно сразу увеличивать.
Соседи ячейки
Соседей ячейки перебирают, меняя индексы строки и столбца на −1, 0 и 1, без самой ячейки и с проверкой границ таблицы. Если соседними считаются ячейки с общей стороной или углом, у ячейки в углу три соседа, на краю — пять, внутри — восемь:
Проверим для каждой ячейки квадрата 3 × 3, есть ли у неё больший сосед. Сдвиг (0, 0) оставляет на месте, его пропускает ; проверку оформим has_larger:
table = [[2, 2, 7], [4, 5, 9], [6, 1, 8]] def has_larger(r, c): x = table[r][c] found = False for dr in [-1, 0, 1]: for dc in [-1, 0, 1]: if dr == 0 and dc == 0: continue nr = r + dr nc = c + dc if ( 0 <= nr < len(table) and 0 <= nc < len(table[0]) ): if table[nr][nc] > x: found = True return found for r in range(len(table)): print([int(has_larger(r, c)) for c in range(3)])Большего соседа нет у девятки и у шестёрки в левом нижнем углу. Проверять границы необходимо: индекс -1 в Python означает последний элемент, и без проверки шестёрка «увидела» бы соседей с правого края — 9 и 8.
В таблице для внутренней ячейки B2 больший сосед есть, если =МАКС(A1:C3)>B2: сама B2 в диапазоне не мешает — она не больше самой себя.
Итого
- Областьстрока, столбец, таблица; $ закрепляет границы
- Другие строкиминус все появления в своей строке, а не 1
- Появления и строкиразные величины
- Два уровняотметки ячеек, затем строк; в Python два прохода
- Соседисдвиги −1, 0, 1 без (0, 0), с проверкой границ
Проверьте себя
Ответь сначала сам, потом открой ответ.
ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Появления в других строках
Число встречается во всей таблице 23 раза, а в текущей строке — 4 раза. Сколько появлений приходится на другие строки?
Введите число.
Подсказка
Вычти все появления в своей строке, а не одно.
Решение
Из всех появлений вычитают все появления в своей строке: 23 − 4 = 19.
Решение программой
print(23 - 4)Ответ: 19
Появления и строки
Число 7 встречается в первой строке дважды, во второй — трижды, в третьей ни разу, в четвёртой — один раз. В скольких строках оно встречается?
Введите число.
Подсказка
Строка учитывается, если число в ней есть хотя бы раз.
Решение
Строка учитывается, если семёрка в ней есть хотя бы раз: первая, вторая и четвёртая — три строки. Появлений при этом шесть — другая величина.
Решение программой
per_row = [2, 3, 0, 1]print(len([k for k in per_row if k > 0]))Ответ: 3
Хорошие ячейки
В каждой строке таблицы 9-10.xlsx, 9-10.txt записаны шесть натуральных чисел. Назовём ячейку хорошей, если её число не встречается в других ячейках этой строки и встречается в других ячейках своего столбца не менее 30 раз. Определи количество строк, содержащих не менее двух хороших ячеек.
Введите число.
Подсказка
Сначала посчитай частоты каждого столбца, затем проверь ячейки; «в других ячейках» — минус сама ячейка.
Решение
Первым проходом считаем частоты каждого столбца, вторым проверяем ячейки: число единственно в строке, а в других ячейках столбца встречается не менее 30 раз — частота столбца минус 1. Строка подходит при двух и более хороших ячейках: таких 276.
Решение программой
from collections import Counter table = []with open("9-10.txt") as f: for line in f: table.append([int(part) for part in line.split()])columns = [Counter(row[j] for row in table) for j in range(6)]answer = 0for a in table: counts = Counter(a) good = 0 for j in range(6): x = a[j] if counts[x] == 1 and columns[j][x] - 1 >= 30: good += 1 if good >= 2: answer += 1print(answer)Ответ: 276
Интересные ячейки
Для таблицы 9-10.xlsx, 9-10.txt назовём ячейку интересной, если её число не встречается в других ячейках этой строки и ровно 160 раз встречается в других строках таблицы. Определи количество строк, содержащих хотя бы одну интересную ячейку.
Введите число.
Подсказка
Появления в других строках — все появления в таблице минус появления в своей строке.
Решение
Появления в других строках — все появления в таблице минус появления в своей строке; у интересной ячейки в своей строке одно появление. Строк хотя бы с одной интересной ячейкой — 253.
Решение программой
from collections import Counter table = []with open("9-10.txt") as f: for line in f: table.append([int(part) for part in line.split()])everywhere = Counter(x for row in table for x in row)answer = 0for a in table: counts = Counter(a) found = 0 for x in a: if counts[x] == 1 and everywhere[x] - counts[x] == 160: found += 1 if found > 0: answer += 1print(answer)Ответ: 253
Ячейки с пятью соседями
В таблице 4 строки и 6 столбцов, соседними считаются ячейки с общей стороной или углом. Сколько ячеек имеют ровно 5 соседей?
Введите число.
Подсказка
Раздели ячейки на внутренние, угловые и остальные краевые.
Решение
Пять соседей у ячеек на краю, кроме угловых. Всего ячеек 24, внутренних (4 − 2) · (6 − 2) = 8 (у них по 8 соседей), угловых 4 (по 3 соседа): 24 − 8 − 4 = 12.
Решение программой
rows, cols = 4, 6inner = (rows - 2) * (cols - 2)corner = 4print(rows * cols - inner - corner)Ответ: 12
Вершины таблицы
Для таблицы 9-10.xlsx, 9-10.txt соседними считаются ячейки с общей стороной или углом. Назовём ячейку вершиной, если её число не встречается в других ячейках этой строки и ни в одной соседней ячейке нет числа больше. Определи количество строк, содержащих хотя бы одну вершину.
Введите число.
Подсказка
Перебирай соседей сдвигами −1, 0 и 1, пропуская саму ячейку и выход за край таблицы.
Решение
Для каждой ячейки перебираем сдвиги −1, 0, 1 без (0, 0) и с проверкой границ. Вершина — число единственно в строке и ни один сосед не больше. Строк хотя бы с одной вершиной — 600.
Решение программой
table = []with open("9-10.txt") as f: for line in f: table.append([int(part) for part in line.split()])n, m = len(table), len(table[0])answer = 0for i in range(n): found = False for j in range(m): x = table[i][j] if table[i].count(x) != 1: continue top = True for di in (-1, 0, 1): for dj in (-1, 0, 1): y, z = i + di, j + dj inside = 0 <= y < n and 0 <= z < m if inside and (di, dj) != (0, 0): if table[y][z] > x: top = False if top: found = True if found: answer += 1print(answer)Ответ: 600