Задание №4 ЕГЭ по информатике: разбор, шаблоны кода Python и анти-примеры | СмартКИМ
СмартКИМ УДОБНАЯ ПОДГОТОВКА К ЕГЭ И ОГЭ
Задачи №4 Решать в тренажере Войти в СмартКИМ
ЕГЭ (1–27) ОГЭ (1–15) Python: шпаргалка
Быстрый переход по номерам и темам
Базовый (1 балл) Время: 3-5 мин Двоичное дерево Прямое условие Фано Обратное условие Фано Python Все задачи №4 в каталоге

Задание №4. Условие Фано: код без путаницы

Тема: Однозначно декодируемые коды, прямое и обратное условие Фано
Буквам назначены двоичные коды, часть кодов известна. Надо подобрать коды остальным буквам так, чтобы сообщение декодировалось однозначно, а длина получилась наименьшей. Решается деревом на бумаге или коротким перебором на Python.

Что от тебя хотят

Есть алфавит из нескольких букв. Для некоторых букв коды уже известны. Остальным нужно выдать коды так, чтобы закодированное сообщение, склеенное в одну строку из нулей и единиц, всегда читалось одним способом. Классический вопрос: «какова наименьшая возможная длина закодированного слова».

Когда код читается однозначно

Достаточно выполнить одно из двух условий:

  • Прямое условие Фано: ни одно кодовое слово не является началом другого. Читаем слева направо и всегда знаем, где кончилась буква.
  • Обратное условие Фано: ни одно кодовое слово не является концом другого. Тогда читаем справа налево.

В условии про «однозначное декодирование» годится любое из двух. Нельзя смешивать: весь набор целиком должен подчиняться одному условию.

Старые разборы учили только прямое условие. Этого мало: в реальных вариантах обратное условие даёт ответ короче, и без него получится на единицу больше.

Дерево кодов

Рисуем двоичное дерево: из каждого узла идут две ветки, 0 влево и 1 вправо. Каждой букве соответствует свой узел. Для прямого условия буква ставится в конец ветки, и всё, что растёт ниже неё, закрыто. Так видно, какие свободные узлы остались, и какой самый короткий из них.

Разбор 1: прямое условие

Буквам А, Б, В, Г назначены коды А: 00, Б: 010, В: 011, Г: 10. Для букв Д и Е нужно выбрать коды по условию Фано так, чтобы код Д был как можно короче, а среди равных по длине имел наименьшее значение. Какой код у Д?

  1. Занято: 00, 010, 011 и 10. Ветка 0 закрыта полностью: 00 внизу слева, а 010 и 011 заняты внизу справа.
  2. Свободная ветка одна: 11. Если отдать её букве Д целиком, для Е ничего не останется.
  3. Значит узел 11 надо разделить: 110 и 111.
  4. Наименьший по значению из них 110.

Ответ: 110.

Разбор 2: можно и обратное условие

Для букв П, Р, О, Б использовали коды 00, 1001, 0101, 111. Алфавит ещё содержит К, Н и И. Код должен допускать однозначное декодирование. Найдите наименьшую возможную длину закодированного слова КОРОН.

  1. Слово КОРОН состоит из К, О, Р, О, Н. Известные части: О = 0101 (дважды) и Р = 1001, это 4 + 4 + 4 = 12 бит. Остаётся длина кодов К и Н.
  2. Свободных кодов длины 2 в прямом режиме нет: ветки 01 и 10 уже заняты (0101 и 1001 растут внутри них). Длины 3 свободны три: 011, 101 и 110. К и Н получат по 3 бита, и всё слово займёт 12 + 6 = 18.
  3. А теперь обратное условие. В нём ни один код не заканчивается другим. Код 10 не заканчивает ни один из известных, и сам не заканчивается на них. Подходит К = 10 (2 бита). Для Н найдём 3 бита: 011. Для И подойдёт 0001, это не мешает, так как И в слове нет.
  4. Итого 12 + 2 + 3 = 17.

Ответ: 17. Проверено перебором: прямое условие даёт 18, обратное даёт 17.

Буква, которой нет в нужном слове, всё равно должна получить код, но он может быть длинным. Не отдавай ей короткий узел, который нужен другим.

Разновидности и прототипы задания на экзамене

Тип 1: Код для одной буквы
Найти кодовое слово наименьшей длины, а при равных длинах с наименьшим числовым значением.
Тип 2: Длина слова при оптимальном кодировании
Часть букв без кода. Подбираем коды так, чтобы заданное слово получилось как можно короче.
Тип 3: Количество подходящих слов
Считаем, сколько существует кодовых слов нужной длины, которые не нарушают условия.

Код решения на Python

Запустить код в онлайн-песочнице
a.startswith(b)a.endswith(b)product("01", repeat=n)set(codes)continuemin(best, ...)
Проверяем, что набор кодов подходит
codes = ["00", "1001", "0101", "111", "10", "011", "0001"]

prefix_ok = True
suffix_ok = True
for a in codes:
    for b in codes:
        if a != b and b.startswith(a):
            prefix_ok = False
        if a != b and b.endswith(a):
            suffix_ok = False

print(prefix_ok, suffix_ok)
Ищем наименьшую длину слова КОРОН
from itertools import product

known = ["00", "1001", "0101", "111"]
short = ["".join(p) for n in range(1, 5) for p in product("01", repeat=n)]
long_words = ["".join(p) for n in range(1, 7) for p in product("01", repeat=n)]

best = 100
for k in short:
    for n in short:
        for i in long_words:
            codes = known + [k, n, i]
            if len(set(codes)) < 7:
                continue
            prefix_ok = True
            suffix_ok = True
            for a in codes:
                for b in codes:
                    if a != b and b.startswith(a):
                        prefix_ok = False
                    if a != b and b.endswith(a):
                        suffix_ok = False
            if prefix_ok or suffix_ok:
                best = min(best, 12 + len(k) + len(n))

print(best)

Типичные ошибки

✕ Не так
Растить ветку из занятого узла
Если у А код 01, нельзя дать Б код 010: 01 стало бы началом 010.
✓ Так
Занятый узел закрывает всё, что ниже него.
✕ Не так
Забыть про оставшиеся буквы
Отдать последний свободный узел одной букве, а ещё двум не оставить ничего.
✓ Так
Свободных узлов должно хватить на все буквы без кода, даже на те, которых нет в слове.
✕ Не так
Проверять только прямое условие
Задача говорит «однозначно декодируется», а ты отбросил более короткий код с обратным условием.
✓ Так
Проверить оба условия и взять лучшее. Смешивать их внутри одного набора нельзя.
ГРОБ

ГРОБ №4: Слово с повторяющимися буквами

В слове «АНАНАС» буква А повторяется три раза, а Н два. Если отдать им одинаковые по длине коды, слово окажется длиннее нужного.

Как обойти
Считай, сколько раз каждая буква входит в слово. Чем чаще буква, тем короче должен быть её код: самым частым отдавай самые короткие свободные узлы.

Лайфхаки на экзамене

  1. При равной длине берут код с наименьшим числовым значением: нули раньше. 100 меньше 101 и 110.
  2. Проверка на бумаге: сумма 2 в степени минус длина каждого кода не больше единицы (неравенство Крафта). Если больше, кодов не хватит.
  3. Длину слова считай по буквам с учётом повторов: О в КОРОН входит дважды, и её код тоже дважды.
Банк реальных задач №4 Открыть в тренажере СмартКИМ