Информатика

7 600 задачвместе с подтемами
Число у задачи — рейтинг сложности, слово рядом — насколько она трудна по сравнению с другими задачами такого же типа. Шкалы задач с ответом и задач с кодом между собой не сравниваются. Рядом — счётчики попыток: успешные, неуспешные.

В школе Ларево пятничная мафия — священная традиция. Дерево предсказывает участие:

              [Пятница?]
              /        \
            Да          Нет
            /             \
     [Домашки много?]   НЕ ПРИДЁТ
        /        \
      Да         Нет
      /            \
[Мафия или домашка?] ПРИДЁТ
    /        \
 Мафия     Домашка
   /          \
ПРИДЁТ    НЕ ПРИДЁТ

Пять учеников в пятницу:

Ученик Много домашки? Выбор
Тимоха Да Мафия
Алиса Нет
Данон Да Домашка
Вика Да Мафия
Костя Нет

Сколько придут на мафию?

    1. 2
    1. 3
    1. 4
    1. 5

Предсказываем, кто забудет сменку.

Начальная энтропия: 1.0 (половина забывает, половина нет)

Разделяем по признаку «Понедельник»:

  • Понедельник (8 человек): энтропия 0.0 (все забыли!)
  • Другой день (12 человек): энтропия 0.65

Чему равна информационная выгода?

    1. 0.21
    1. 0.39
    1. 0.61
    1. 1.0

Данные: кто нарисовал усы на портрете Пушкина?

Был на перемене в кабинете? Имеет маркер? Смеялся громче всех? Виновен?
1 Да Да Да
2 Да Да Нет
3 Да Нет Да
4 Да Нет Нет
5 Нет Да Да
6 Нет Да Нет
7 Нет Нет Да
8 Нет Нет Нет

Какой признак лучше всего разделяет виновных?

    1. Был в кабинете
    1. Имеет маркер
    1. Смеялся громче всех
    1. Нужны все три вместе

(вопрос с подвохом) 

Дерево учителя информатики:

                [Телефон на парте?]
                 /              \
               Да               Нет
               /                  \
      [Вика смотрит в него?]   НЕ КОНФИСКУЮТ
          /           \
        Да            Нет
        /               \
  КОНФИСКУЮТ     [Звук включён?]
                    /        \
                  Да         Нет
                  /            \
            КОНФИСКУЮТ    НЕ КОНФИСКУЮТ

Ситуация: телефон на парте, Вика смотрит в окно, но телефон вдруг играет «Never Gonna Give You Up».

Что случится?

    1. Не конфискуют — она же не смотрит!
    1. Конфискуют
    1. Учитель посмеётся и простит
    1. Рикролл защитит телефон

В столовой школы Ларево продают пиццу. Очередь:

День 1: Все 30 человек взяли пиццу 🍕🍕🍕

День 2: 15 взяли пиццу, 15 взяли салат 🍕🥗

В какой день энтропия выбора ВЫШЕ?

    1. День 1 — пиццы больше
    1. День 2 — выбор разделился
    1. Одинаково
    1. Энтропия не работает с пиццей

Дерево решает, будет ли Данон есть на уроке:

           [Прошло больше часа с завтрака?]
                  /                \
                Да                 Нет
                /                    \
        [Учитель строгий?]       НЕ БУДЕТ ЕСТЬ
           /          \
         Да           Нет
         /              \
    БУДЕТ ЕСТЬ      БУДЕТ ЕСТЬ
    (тихо)          (громко хрустя)

Что является ЛИСТОМ дерева?

    1. «Прошло больше часа с завтрака?»
    1. «Учитель строгий?»
    1. «БУДЕТ ЕСТЬ (тихо)»
    1. «Да» и «Нет»

У вас есть дерево для предсказания, понравится ли фильм:

                [Жанр = Ужасы?]
                /            \
              Да              Нет
              /                \
        НЕ ПОНРАВИТСЯ     [Есть супергерои?]
                            /           \
                          Да            Нет
                          /              \
                   ПОНРАВИТСЯ      [Длительность > 2ч?]
                                      /          \
                                    Да           Нет
                                    /             \
                              НЕ ПОНРАВИТСЯ   ПОНРАВИТСЯ

Маша идёт на фильм: комедия, без супергероев, длится 1.5 часа. Что предскажет дерево?

  1. Понравится
  2. Не понравится
  3. Невозможно определить
  4. Нужно больше данных

В деревьях решений для работы с непрерывными признаками нужно найти  оптимальный порог разделения.

Порог — это число, которое делит данные  на две части: значения ≤ порога идут влево, значения > порога — вправо.

 

Пример:

Значения:  [1, 3, 5, 7, 9]
Метки:     [0, 0, 1, 1, 1]

Если выбрать порог = 4:
- Левая часть (≤ 4): значения [1, 3], метки [0, 0]
- Правая часть (> 4): значения [5, 7, 9], метки [1, 1, 1]

Это хорошее разделение! Левая часть чистая, правая чистая.


Алгоритм поиска лучшего порога:

1. Отсортируй уникальные значения признака
2. Для каждой пары соседних уникальных значений:
   - Порог = среднее этих двух значений
   - Раздели данные по порогу
   - Посчитай информационную выгоду
3. Верни порог с максимальной выгодой

Реализуйте алгоритм поиска лучшего порога.


Формат входных данных
- Первая строка: N — количество элементов
- Вторая строка: N вещественных чисел — значения признака
- Третья строка: N целых чисел (0 или 1) — метки классов

Формат выходных данных
- Первая строка: оптимальный порог (вещественное число, 4 знака после запятой)
- Вторая строка: информационная выгода (вещественное число, 4 знака после запятой)

Теперь соберём все части вместе и создадим полноценное дерево решений!

Дерево решений — это алгоритм машинного обучения, который:
1. Находит лучший признак для разделения данных (по информационной выгоде)
2. Рекурсивно строит поддеревья для каждой части
3. Останавливается, когда данные "чистые" или достигнута максимальная глубина

Пример работы на данных OR (логическое ИЛИ):
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 1, 1, 1]

Дерево может выглядеть так:
            [feature 0]
             /       \
        x[0]=0      x[0]=1
           /           \
      [feature 1]    лист(1)
       /      \
   лист(0)  лист(1)

Задача

Используйте класс TreeNode, реализованный в предыдущем задании.
Реализуйте класс DecisionTree с методами:

0.  __init__(self, max_depth=10)`
   Инициализирует дерево решений.
   
   Параметры:
   - max_depth: максимальная глубина дерева (по умолчанию 10)
   Что нужно сделать:
   - Сохранить max_depth как атрибут объекта
   - Создать атрибут self.root и установить его в None (корень дерева будет создан позже при вызове fit)

1. entropy(self, labels)
   Считает энтропию списка меток.
   H = -p₀·log₂(p₀) - p₁·log₂(p₁)
   Если список пустой, возвращает 0.
   Если p=0, соответствующее слагаемое = 0.

2. find_best_split(self, X, y)
   Находит лучший признак для разделения.
   - Для каждого признака считает информационную выгоду
   - Возвращает кортеж: (индекс_лучшего_признака, информационная_выгода)
   - Если все признаки дают нулевую выгоду, возвращает (0, 0)

3. build_tree(self, X, y, depth=0)
   Рекурсивно строит дерево. Возвращает TreeNode.
   
   Условия остановки (создать лист):
   - Все метки одинаковые → лист с этой меткой
   - Достигнута max_depth → лист с самым частым классом
   - Нет признаков (X пустой или X[0] пустой) → лист с самым частым классом
   - Лучшее разделение даёт нулевую выгоду → лист с самым частым классом
   
   Иначе:
   - Найти лучший признак
   - Разделить данные: левая часть где x[feature]=0, правая где x[feature]=1
   - Рекурсивно построить поддеревья
   - Вернуть TreeNode с feature_index и поддеревьями

4. fit(self, X, y) - берёт данные (примеры X и ответы y) и строит из них дерево решений, которое потом будет делать предсказания.

5. predict(self, X) - берёт новые данные и для каждого примера спрашивает у дерева: "Какой ответ?"
 

Класс TreeNode уже реализован в предыдущем задании. Скопируйте его здесь.
Примеры
Пример 1
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 1, 1, 1]
tree = DecisionTree(max_depth=3)
tree.fit(X, y)
tree.predict(X)  # [0, 1, 1, 1]
Пример 2
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 0, 0, 1]
tree = DecisionTree(max_depth=3)
tree.fit(X, y)
tree.predict(X)  # [0, 0, 0, 1]
Пример 3
X = [[0,0], [0,1], [1,0], [1,1]]
y = [1, 1, 1, 0]
tree = DecisionTree(max_depth=3)
tree.fit(X, y)
tree.predict(X)  # [1, 1, 1, 0]
Дан список меток (0 и 1) до разделения и два списка после разделения 
на левую и правую части. Вычисли информационную выгоду.

Формат входных данных
- Первая строка: N — количество элементов до разделения
- Вторая строка: N чисел (0 или 1) — метки до разделения
- Третья строка: L — количество элементов в левой части
- Четвёртая строка: L чисел (0 или 1) — метки левой части
- Пятая строка: R — количество элементов в правой части
- Шестая строка: R чисел (0 или 1) — метки правой части

Гарантируется, что L + R = N и L, R > 0.

Формат выходных данных
Одно число — информационная выгода, округлённое до 4 знаков после запятой.
Разбирая старые задачи олимпиады, Петя наткнулся на алгоритм рекурсивного закрашивания растрового изображения. У Пети есть черно-белое (bitmap) изображение размером 13 на 13 пикселей. На изображении присутствует замкнутый контур, как приведено на рисунке. Пиксели внутри контура пронумерованы.


Традиционно для компьютерной графики, система координат имеет начало в верхнем левому углу, ось X направлена слева направо, а ось Y – сверху вниз.
Алгоритм рекурсивного закрашивания заключается в рекурсивном вызове процедуры «Закрасить», которой передаются два параметра – координаты X и Y пикселя.
Процедура Закрасить(X, Y), может быть описана следующим образом:
1. Если цвет пикселя с координатами (X, Y) белый, то:
a. Изменить цвет пикселя с этими координатами на черный;
b. Вызвать процедуру Закрасить(X+1, Y);
c. Вызвать процедуру Закрасить(X, Y+1);
d. Вызвать процедуру Закрасить(X-1, Y);
e. Вызвать процедуру Закрасить(X, Y-1);
2.Иначе завершить процедуру.
Известно, что последний закрашенный пиксель, перед завершением процедуры, имел номер 29. Сколько существует пикселей внутри контура, в которых можно исходно вызвать процедуру «Закрасить» так, чтобы получить такой результат?

В ответе укажите целое число.
Поделиться
Класснуть