Изучаем Python для успешной сдачи ЕГЭ: алгоритмы и код
Решение задач ЕГЭ по информатике требует не только знания синтаксиса Python, но и умения выбирать эффективные алгоритмы, избегать типичных ошибок и правильно интерпретировать условия. В этой статье рассмотрены подходы к решению нескольких распространенных типов заданий с примерами кода и подробными пояснениями.
Основные стратегии и примеры решений
Как построить таблицу истинности для логической функции?
Наиболее эффективный способ - использовать цикл по всем наборам переменных. Для четырёх переменных (x, y, z, w) функция вычисляется напрямую.
for x in (0,1):
for y in (0,1):
for z in (0,1):
for w in (0,1):
f = int((x and y) or (not z) and w)
print(x, y, z, w, f)решение задач егэ python (решение задач егэ по информатике на python)
Этот код выводит все комбинации и значение функции.
Вариант с модулем itertools позволяет сократить код и легче масштабируется:
from itertools import product
for x,y,z,w in product((0,1), repeat=4):
f = int((x and y) or (not z) and w)
print(x,y,z,w,f)задачи с решениями с циклами python (задачи на циклы с решениями в python)
Типичная ошибка - неправильное определение приоритета операций. Рекомендуется явно расставлять скобки. Также важно помнить, что Python возвращает булевы значения; для числового вывода используется функция int(). Не следует путать операторы and и or с побитовыми & и |.
Как найти числа, удовлетворяющие условиям перевода в другую систему счисления?
Эффективное решение заключается в переборе чисел в заданном диапазоне и проверке условий с помощью функции перевода в произвольную систему счисления. Пример задачи: найти все числа от 1 до 1000, у которых в троичной записи ровно две цифры 2.
def to_base(n, base):
digits = []
while n > 0:
digits.append(n % base)
n //= base
return ''.join(str(d) for d in reversed(digits))
result = []
for num in range(1, 1001):
trinary = to_base(num, 3)
if trinary.count('2') == 2:
result.append(num)
print(result[:10])
задача примеры python (примеры задач по python с решениями)
[5, 6, 7, 14, 15, 16, 19, 20, 21, 23]
Альтернативный подход - использовать представление числа в виде списка цифр с помощью деления на основание. Можно также применять встроенные функции format для оснований 2, 8, 16, но для произвольного основания потребуется собственная реализация.
# Использование рекурсии
def to_base_rec(n, base):
if n < base:
return str(n)
return to_base_rec(n // base, base) + str(n % base)
Типичные ошибки: неправильная обработка нуля (число 0 в любой системе записывается как '0'), забывают про ведущие нули (они не учитываются). Также возможна путаница при преобразовании цифр больше 9 (например, в 16-ричной системе). Для ЕГЭ достаточно оснований до 9, поэтому проблема цифр-букв не возникает.
Как обрабатывать строки с заменой по правилам?
Оптимальный способ - организовать цикл, который последовательно заменяет вхождения подстрок до тех пор, пока это возможно. Используется метод replace с ограничением количества замен (count=1).
s = '121212'
while '12' in s:
s = s.replace('12', '21', 1)
print(s)
212112
Пояснение: цикл продолжается, пока в строке есть подстрока '12'. Каждая замена затрагивает только первое вхождение, что позволяет обрабатывать перекрывающиеся шаблоны.
Другой вариант - использовать регулярные выражения. Это удобно для сложных шаблонов, но может быть медленнее и требует импорта библиотеки re.
import re
s = '121212'
while '12' in s:
s = re.sub('12', '21', s, count=1)
print(s)
Частая проблема - бесконечный цикл, когда замена снова порождает заменяемую подстроку. Например, при замене 'aa' на 'a' в строке 'aaa'. В таких случаях нужно ограничивать количество итераций либо использовать фиксированное число замен. Для задач ЕГЭ бесконечного цикла обычно не возникает, но следует проверять условие выхода.
Как посчитать количество путей в графе?
Эффективный способ - динамическое программирование. Количество путей в вершину равно сумме путей из всех предшествующих вершин. Для ациклических графов можно обрабатывать вершины в порядке топологической сортировки.
# Граф задан списком смежности (ориентированный ациклический)
graph = {
1: [2, 3],
2: [3, 4],
3: [5],
4: [5],
5: []
}
start, end = 1, 5
dp = {v: 0 for v in graph}
dp[start] = 1
# Топологический порядок (известен заранее, можно использовать обход)
order = [1,2,3,4,5]
for v in order:
for u in graph[v]:
dp[u] += dp[v]
print(dp[end])
3
Рекурсивный обход с мемоизацией (декоратор lru_cache из functools) также подходит для небольших графов.
from functools import lru_cache
graph = {1: [2,3], 2:[3,4], 3:[5], 4:[5], 5:[]}
@lru_cache(maxsize=None)
def paths(v):
if v == 5:
return 1
return sum(paths(u) for u in graph[v])
print(paths(1))
Ошибки: не учитывают направленность ребер (если граф неориентированный, нужно избегать повторного посещения). Также возможна рекурсия до бесконечности при наличии циклов. Для ациклических графов порядок вершин должен быть строгим; если топологическая сортировка не задана, её нужно вычислить.
Как вычислить значение рекурсивной функции без переполнения стека?
Для функций с глубокой рекурсией лучше использовать итеративный подход с запоминанием промежуточных значений (динамическое программирование). Пример: F(n) = n, если n < 3; иначе F(n-1) + 2*F(n-2). Вычислить F(50).
n = 50
f = [0] * (n+1)
f[0] = 0
f[1] = 1 # хотя по условию n<3, начнём с 0 и 1
f[2] = 2
for i in range(3, n+1):
f[i] = f[i-1] + 2 * f[i-2]
print(f[n])
12297829382473034410
Этот код выполняется за O(n) и не использует рекурсию.
Можно использовать рекурсию с кэшированием (lru_cache) и увеличенным лимитом глубины рекурсии.
import sys
sys.setrecursionlimit(10000)
from functools import lru_cache
@lru_cache()
def F(n):
if n < 3:
return n
return F(n-1) + 2*F(n-2)
print(F(50))
Типичные проблемы: превышение глубины рекурсии для n > 1000, если не установлен лимит. Также рекурсия без кэширования приводит к экспоненциальному времени выполнения. Важно правильно определить базовые случаи; в заданиях ЕГЭ часто дают функции с двумя условиями.
Как обработать последовательность чисел из файла и найти пары по условию?
Считываем все числа в список, затем проходим по всем парам с помощью вложенных циклов. Для уменьшения числа операций можно использовать перебор только по индексам i < j, если пары неупорядочены.
with open('data.txt') as f:
nums = [int(line) for line in f]
count = 0
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if (nums[i] + nums[j]) % 8 == 0 and (nums[i] * nums[j]) % 2 != 0:
count += 1
print(count)
Для больших файлов (более 10000 чисел) вложенный цикл может быть медленным. Оптимизация - группировать числа по остаткам от деления.
from collections import defaultdict
with open('data.txt') as f:
nums = [int(line) for line in f]
mods = defaultdict(list)
for v in nums:
mods[v % 8].append(v)
count = 0
# Пары с остатком i и j, где (i+j) % 8 == 0
for i in range(8):
for j in range(i, 8):
if (i + j) % 8 == 0:
if i == j:
count += len(mods[i]) * (len(mods[i]) - 1) // 2
else:
count += len(mods[i]) * len(mods[j])
# Дополнительная проверка на нечетность произведения – требует уточнения
print(count)
Этот подход сокращает время с O(n^2) до O(n + 64).
Ошибки: неверная индексация при чтении файла (забывают преобразовать строку в число), путают упорядоченные и неупорядоченные пары. При оптимизации с остатками легко пропустить условие на нечетность произведения; его нужно учитывать отдельно.
Расширенные примеры и нестандартные приёмы
Оптимизация поиска чисел с заданным количеством делителей
Для задания 25 (поиск чисел с определённым числом делителей) часто требуется перебирать делители до квадратного корня. Пример: найти все числа от 1 до 10000, у которых ровно 5 делителей.
def count_divisors(n):
cnt = 0
i = 1
while i*i <= n:
if n % i == 0:
cnt += 2 если i*i != n else 1
i += 1
return cnt
result = [num for num in range(2, 10001) if count_divisors(num) == 5]
print(result[:10])
[16, 81, 625, 2401]
Объяснение: число с ровно 5 делителями имеет вид p^4, где p - простое. Код проверяет все числа и находит такие.
Использование deque для обхода графа в ширину (BFS)
Задачи на кратчайшие пути или количество шагов часто решаются BFS. Модуль collections.deque обеспечивает эффективную очередь.
from collections import deque
graph = {
1: [2,3],
2: [4,5],
3: [5],
4: [6],
5: [6],
6: []
}
start, target = 1, 6
queue = deque([(start, 0)])
visited = {start}
while queue:
v, dist = queue.popleft()
if v == target:
print(dist)
break
for u in graph[v]:
if u not in visited:
visited.add(u)
queue.append((u, dist+1))
3
Применение Counter для частотного анализа строк
В задании 12 иногда требуется посчитать количество различных символов или длину цепочек. Класс Counter из collections упрощает подсчёт.
from collections import Counter
s = 'abracadabra'
cnt = Counter(s)
print(cnt.most_common(3))
[('a', 5), ('b', 2), ('r', 2)]
Это позволяет быстро найти самые частые символы.