Изучаем Python для успешной сдачи ЕГЭ: алгоритмы и код

Раздел: 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)]

Это позволяет быстро найти самые частые символы.

Решение задач ЕГЭ по информатике на Python - comments

En
решение задач егэ python (python)