ЕГЭ
Информатика
2 сентября 2026
20 минут чтения

Задание 23 ЕГЭ по информатике: графы, кратчайший путь и количество путей

Задание 23 ЕГЭ по информатике (КЕГЭ) — новое с 2027 года. Прежняя тема этой позиции («умение анализировать ход исполнения алгоритма») переехала на задание 13, а на позицию 23 ФИПИ поставил алгоритмические задачи на анализ графов: построение оптимального пути между вершинами графа и определение количества различных путей между вершинами ориентированного ациклического графа. По кодификатору это элемент содержания 2.13 и код требования 2.7. Задание повышенного уровня сложности, за него дают 1 первичный балл, ответ — одно число. С 2027 года задание 23 выполняется с использованием прилагаемого файла и требует компьютера: данные о графе лежат в текстовом файле, и решать вручную их нельзя. Примерное время выполнения — 12 минут. В статье — формат входного файла, рабочий код на Python для обеих подзадач, разбор демоверсии 2027 года и учебные примеры, на которых метод виден целиком. Потренироваться можно на заданиях 23 ЕГЭ по информатике онлайн.

Что проверяет задание 23 ЕГЭ по информатике

Формулировка обобщённого плана варианта КИМ 2027 года дословно: «Умение решать алгоритмические задачи, связанные с анализом графов (задачи построения оптимального пути между вершинами графа, определения количества различных путей между вершинами ориентированного ациклического графа)». То есть под одним номером стоят две родственные подзадачи, и вариант может спросить любую из них.

ПараметрЗначение
Максимальный балл1 первичный (частичного зачёта нет: ответ либо совпал с эталоном, либо 0)
Уровень сложностиПовышенный (П) — одно из 11 заданий этого уровня в работе
Формат ответаКраткий: одно целое число
Раздел кодификатора2. Теоретические основы информатики; КЭС 2.13 «Графы»; код требования 2.7
Нужен ли файл / спец. ПОДа — к заданию прилагается текстовый файл с описанием графа, нужна среда программирования
Примерное время выполнения12 минут (Обобщённый план варианта КИМ, СПЕЦ ЕГЭ-2027 по информатике)
Связанные заданияЗадание 1 (схема дорог как граф, но вручную и без файла), задание 22 (граф зависимостей процессов), задание 13 (тот же приём «динамика по состояниям»)

Тренируйтесь на заданиях КЕГЭ

Задания 23 ЕГЭ по информатике с мгновенной проверкой ответа. Решаем, ошибаемся, разбираем — бесплатно.

Как выглядит формулировка

Ниже — задание 23 из демоверсии ЕГЭ 2027 года дословно. Обратите внимание на строку «Задание выполняется с использованием прилагаемого файла» над номером: она означает, что в тестирующей системе к заданию прикреплён файл, и без него условие неполно.

Задание 23

Демоверсия ЕГЭ 2027 по информатике

В текстовом файле содержится описание ациклического ориентированного взвешенного графа. В каждой строке файла записаны два натуральных числа (L, M) и одно положительное вещественное число (W). L и M – номера вершин графа, W – вес ребра, ведущего из вершины L в вершину M. Таким образом, количество строк в файле равно количеству рёбер в графе. Две вершины графа не могут быть соединены более чем одним ребром.

Найдите и запишите в ответе целую часть длины кратчайшего пути из вершины с номером 1 в вершину с номером 100. Существование хотя бы одного такого пути гарантируется. Под длиной кратчайшего пути понимается минимальная сумма весов рёбер, составляющих путь.

Для выполнения этого задания следует написать программу.

Вершины графа могут быть пронумерованы не подряд. L ≤ 1000, M ≤ 1000; W ≤ 10 000. Количество строк в файле не превосходит 200. Числа в строках разделены произвольным ненулевым количеством пробелов и/или табуляций.

К условию ФИПИ прикладывает типовой пример — маленький файл, по которому видно и формат строк, и смысл ответа:

100   12      1.0
6     7       7.0
6     1       1.0
1     7       5.5
7     100     2.0
4     100     8.0
1     100     12.0
1     4       2.5

Из вершины 1 в вершину 100 здесь ведут три пути: 11001 \to 100 длиной 12, 141001 \to 4 \to 100 длиной 2,5+8=10,52{,}5 + 8 = 10{,}5 и 171001 \to 7 \to 100 длиной 5,5+2=7,55{,}5 + 2 = 7{,}5. Минимум — 7,5, целая часть — 7: именно это число ФИПИ и называет верным ответом для типового примера. Рёбра 10012100 \to 12, 676 \to 7 и 616 \to 1 в ответ не попадают вовсе — они лежат в стороне от маршрута, и это нормально: файл описывает весь граф, а не только нужный путь.

Второй подтип этой же линии — количество путей. У него формулировка короче: дан ориентированный ациклический граф, нужно определить, сколькими различными путями можно попасть из одной заданной вершины в другую. Веса в такой задаче не нужны, а ответ — тоже одно целое число, только оно бывает очень большим (миллионы и миллиарды), и это не повод искать ошибку.

Теория: всё, что нужно для задания 23

Граф, вершины, рёбра, вес

  • Граф — набор вершин и соединяющих их рёбер. Вершины на КЕГЭ всегда пронумерованы натуральными числами.
  • Ориентированный граф (орграф) — рёбра имеют направление: ребро из LL в MM не даёт права пройти из MM в LL.
  • Взвешенный граф — каждому ребру приписано число, его вес. В задании 23 вес — положительное вещественное число, а длина пути — сумма весов входящих в него рёбер.
  • Ациклический граф — в нём нельзя, идя по стрелкам, вернуться в ту же вершину. Именно ацикличность делает подсчёт количества путей конечной задачей: в графе с циклом путей было бы бесконечно много.
  • Путь — последовательность вершин, в которой каждая следующая соединена с предыдущей ребром нужного направления.

Формат файла: три числа в строке

Каждая строка файла — одно ребро: L M W. Числа разделены «произвольным ненулевым количеством пробелов и/или табуляций», поэтому единственный правильный способ разобрать строку — split() без аргументов: он сам съедает любое количество любых пробельных символов.

graph = {}
for line in open('23.txt'):
    parts = line.split()
    if len(parts) != 3:
        continue
    a, b, w = int(parts[0]), int(parts[1]), float(parts[2])
    graph.setdefault(a, []).append((b, w))

Проверка len(parts) != 3 нужна ради последней пустой строки файла — без неё программа падает на int(parts[0]). Словарь graph хранит список смежности: для каждой вершины — список пар «куда» и «сколько стоит». Ребро добавляется только один раз, потому что граф ориентированный.

Подзадача 1: кратчайший путь — алгоритм Дейкстры

Идея алгоритма Дейкстры: держим для каждой вершины vv текущую оценку d[v]d[v] — длину самого короткого известного пути из старта. В начале d[1]=0d[1] = 0, у остальных вершин оценки нет. Дальше повторяем один шаг: берём непросмотренную вершину с наименьшей оценкой, объявляем её оценку окончательной и «расслабляем» все исходящие из неё рёбра:

d[u]min(d[u], d[v]+w(v,u)).d[u] \leftarrow \min\bigl(d[u],\ d[v] + w(v, u)\bigr).

Почему первую же вынутую вершину можно считать готовой: веса положительны, поэтому любой другой путь до неё пройдёт через вершину с оценкой не меньше текущей и станет только длиннее. Именно на этом условии — веса неотрицательны — алгоритм и держится; в задании 23 оно записано в условии словами «положительное вещественное число».

«Взять вершину с наименьшей оценкой» быстрее всего делает куча — модуль heapq из стандартной библиотеки Python:

import heapq

INF = float('inf')
dist = {1: 0.0}
queue = [(0.0, 1)]
while queue:
    d, v = heapq.heappop(queue)
    if d > dist.get(v, INF):
        continue
    for u, w in graph.get(v, []):
        if d + w < dist.get(u, INF):
            dist[u] = d + w
            heapq.heappush(queue, (d + w, u))

print(int(dist[100]))

int() для положительного числа — это и есть целая часть, отбрасывание дробной части: int(7.5) даёт 7. Не пишите round() — он даст 8 и обнулит задание.

Тот же ответ без Дейкстры: 200 проходов по рёбрам

Если куча и «непросмотренные вершины» кажутся лишней конструкцией на экзамене, есть код короче и его почти невозможно написать неправильно. Рёбер по условию не больше 200, значит и вершин на любом пути не больше 201. Просто расслабляем все рёбра подряд столько раз, сколько рёбер в файле, пока хоть что-то меняется:

INF = float('inf')
dist = {1: 0.0}
for _ in range(len(edges)):
    changed = False
    for a, b, w in edges:
        if dist.get(a, INF) + w < dist.get(b, INF):
            dist[b] = dist[a] + w
            changed = True
    if not changed:
        break

print(int(dist[100]))

Это алгоритм Беллмана — Форда. Он медленнее Дейкстры, но при 200 рёбрах разница незаметна: 200 × 200 = 40 000 операций, миллисекунды. На демоверсии 2027 года оба варианта дают одинаковый ответ.

Подзадача 2: количество путей — динамика по вершинам

Пусть P[v]P[v] — количество различных путей из вершины vv в конечную вершину TT. Тогда P[T]=1P[T] = 1 (пустой путь), а для любой другой вершины путь начинается с одного из исходящих рёбер:

P[v]=vuP[u].P[v] = \sum_{v \to u} P[u].

Веса здесь не участвуют вообще. Ацикличность гарантирует, что рекурсия закончится: по стрелкам нельзя вернуться назад, поэтому каждая вершина считается ровно один раз. Кэш count превращает экспоненциальный перебор в линейный по числу рёбер:

count = {}

def paths(v):
    if v == 100:
        return 1
    if v in count:
        return count[v]
    count[v] = sum(paths(u) for u, w in graph.get(v, []))
    return count[v]

print(paths(1))

Тупик обрабатывается сам собой: если из вершины не выходит ни одного ребра, sum по пустому списку даёт 0 — путей из неё в конец нет. Целые числа в Python не переполняются, поэтому ответ в миллиарды писать можно как есть.

Когда обе подзадачи встречаются в одном варианте

Формулировка плана перечисляет обе задачи через запятую, значит вариант вправе спросить любую. Хорошая новость: обе решаются одной и той же заготовкой — «прочитать файл в список смежности, а потом посчитать по вершинам». Отличается только то, что накапливается: в первой задаче — минимум суммы весов, во второй — сумма количеств. Поэтому держите в голове один шаблон чтения файла и две короткие концовки к нему.

Алгоритм решения задания 23

  1. Прочитайте вопрос до конца и определите подтип: «кратчайший путь» или «сколько различных путей». От этого зависит вся вторая половина программы.
  2. Выпишите номера двух вершин — откуда и куда. В демоверсии это 1 и 100, но в другом варианте числа будут другими, а «1 и 100» въедаются в память слишком легко.
  3. Откройте файл и посмотрите на первые строки глазами: сколько чисел в строке, целые они или вещественные, есть ли заголовок. Формат задан условием, но 10 секунд проверки дешевле получаса отладки.
  4. Постройте список смежности graph.setdefault(a, []).append((b, w)). Ребро добавляется один раз: граф ориентированный.
  5. Посчитайте ответ — Дейкстрой (или 200 проходами релаксации) для кратчайшего пути, динамикой по вершинам для количества путей.
  6. Возьмите целую часть через int(), если спрашивали длину. Для количества путей ничего округлять не нужно — это уже целое число.
  7. Проверьте здравым смыслом. Кратчайший путь не может быть длиннее любого пути, который вы найдёте вручную, и не может быть меньше веса самого лёгкого ребра, выходящего из старта. Количество путей не может быть нулём, если задача гарантирует существование пути.

Проверьте метод на практике

Каталог заданий ЕГЭ по информатике с мгновенной проверкой ответа и разбором каждой ошибки.

Примеры с разбором

Пример 1 (учебный): кратчайший путь на семи рёбрах

Граф задан таким файлом. Формат тот же, что в задании 23: номер вершины, номер вершины, вес ребра.

1  2  4.0
1  3  1.5
3  2  1.2
2  5  2.5
3  4  6.0
4  5  1.0
2  4  3.0

Вопрос: целая часть длины кратчайшего пути из вершины 1 в вершину 5.

Из вершины 1 выходят два ребра — в 2 (вес 4) и в 3 (вес 1,5). Считаем оценки по Дейкстре, каждый раз выбирая наименьшую из неокончательных:

d[1] = 0     -> расслабляем 1->2 (4.0) и 1->3 (1.5)
d[3] = 1.5   -> 3->2: 1.5 + 1.2 = 2.7 < 4.0, обновляем
                3->4: 1.5 + 6.0 = 7.5
d[2] = 2.7   -> 2->5: 2.7 + 2.5 = 5.2
                2->4: 2.7 + 3.0 = 5.7 < 7.5, обновляем
d[5] = 5.2   -> вершина 5 вынута из кучи, ответ готов
d[4] = 5.7   (уже не влияет: 5.7 + 1.0 = 6.7 > 5.2)

Кратчайший путь — 13251 \to 3 \to 2 \to 5 с длиной 1,5+1,2+2,5=5,21{,}5 + 1{,}2 + 2{,}5 = 5{,}2. Целая часть — 5.

Проверка здравым смыслом: прямой путь 1251 \to 2 \to 5 даёт 4+2,5=6,54 + 2{,}5 = 6{,}5, а путь через вершину 4 — не меньше 6,7. Ответ 5,2 меньше обоих, но больше веса самого лёгкого ребра из вершины 1 (1,5) — значит, в правдоподобных границах. Заметьте главное: жадный выбор «пойти по самому дешёвому ребру и всё» тут случайно сработал, а вот жадный выбор «пойти по самому дешёвому ребру из вершины 3» (это 323 \to 2) дальше уже не гарантирует ничего — работает только полная процедура Дейкстры.

Пример 2 (учебный): количество путей в ациклическом орграфе

Веса здесь не нужны, поэтому оставим только пары вершин:

1 2
1 3
2 4
3 4
2 5
3 5
4 5
4 6
5 6

Вопрос: сколько существует различных путей из вершины 1 в вершину 6. Считаем P[v]P[v] от конца к началу — от вершины с наибольшим номером к вершине 1 (в этом графе стрелки всегда идут от меньшего номера к большему, поэтому такой порядок и есть топологический):

P[6] = 1                          (конечная вершина)
P[5] = P[6]               = 1
P[4] = P[5] + P[6] = 1 + 1 = 2
P[3] = P[4] + P[5] = 2 + 1 = 3
P[2] = P[4] + P[5] = 2 + 1 = 3
P[1] = P[2] + P[3] = 3 + 3 = 6

Ответ — 6. Проверяем перечислением, благо граф крошечный: 1→2→4→5→6, 1→2→4→6, 1→2→5→6, 1→3→4→5→6, 1→3→4→6, 1→3→5→6. Ровно шесть.

Обратите внимание на вершину 4: путь 1→2→4→5→6 и путь 1→2→4→6 различаются только хвостом после вершины 4, и динамика считает этот хвост один раз — в значении P[4]=2P[4] = 2. Именно поэтому метод работает и на графе с тысячей вершин, где путей триллионы.

Пример 3: демоверсия 2027 года целиком

Приложенный к демоверсии файл содержит 200 строк — ровно верхняя граница из условия. Номера вершин доходят до 998, но реально в файле встречаются только 50 различных вершин, веса лежат в диапазоне от 44,0 до 9988,0. Руками такой граф не разобрать — и в этом смысл перевода задания в «компьютерные».

Полная программа решения:

import heapq

graph = {}
for line in open('23.txt'):
    parts = line.split()
    if len(parts) != 3:
        continue
    a, b, w = int(parts[0]), int(parts[1]), float(parts[2])
    graph.setdefault(a, []).append((b, w))

INF = float('inf')
dist = {1: 0.0}
queue = [(0.0, 1)]
while queue:
    d, v = heapq.heappop(queue)
    if d > dist.get(v, INF):
        continue
    for u, w in graph.get(v, []):
        if d + w < dist.get(u, INF):
            dist[u] = d + w
            heapq.heappush(queue, (d + w, u))

print(int(dist[100]))   # 10971

Программа печатает 10971 — это и есть ответ демоверсии. Кратчайший путь проходит через двенадцать рёбер:

1 → 173 → 975 → 625 → 312 → 633 → 825 → 96 → 59 → 698 → 221 → 56 → 100
2034 + 278 + 44 + 193 + 93 + 1508 + 1112 + 443 + 1987 + 459 + 2547 + 273 = 10971

Проверка здравым смыслом: из вершины 1 выходит 12 рёбер, и самое лёгкое из них весит меньше 2034 — то есть жадный первый шаг кратчайшего пути не совпадает с самым дешёвым ребром. Это типичная картина: если ваша программа выдаёт заметно меньшее число, скорее всего вы случайно сделали граф неориентированным и «прошли» по ребру против стрелки.

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

Как задание 23 связано с остальным экзаменом

Всего в КИМ ЕГЭ по информатике 27 заданий, максимальный первичный балл — 29, на всю работу отводится 235 минут. Задание 23 — единственное, где граф задан файлом и требует настоящего алгоритма на графах:

  • Задание 1 — тот же объект, но с другой стороны: схема дорог в виде графа и таблица расстояний, которые нужно сопоставить вручную. Хороший разогрев перед 23-м: там вы учитесь читать граф, здесь — обрабатывать его программой;
  • Задание 22 — граф зависимостей вычислительных процессов, тоже из файла. Самое близкое к 23-му по технике: там тоже считается величина для каждой вершины через её предшественников;
  • Задание 13 — прежний «хозяин» позиции 23. Приём тот же самый: динамика по состояниям, только состояние там — число на экране, а здесь — вершина графа;
  • Задание 16 — рекуррентные выражения; рекурсия с кэшированием там и здесь пишется одинаково.

План подготовки

Неделя 1: язык графов

Разберитесь с терминами: вершина, ребро, ориентированное ребро, вес, путь, цикл, ациклический граф. Нарисуйте на бумаге пять маленьких графов по 5–7 вершин и для каждого выпишите список смежности. Научитесь по списку строк «L M W» восстанавливать картинку и обратно — по картинке писать файл.

Неделя 2: чтение файла и список смежности

Напишите одну функцию чтения файла и доведите её до автоматизма: split(), проверка длины, int для вершин и float для веса, setdefault для словаря. Прогоните её на типовом примере из демоверсии и убедитесь, что получаются ровно восемь рёбер и шесть вершин.

Неделя 3: два алгоритма

Напишите Дейкстру с heapq и вариант с релаксацией всех рёбер — и убедитесь, что на одном и том же файле они дают одинаковый ответ. Отдельно напишите подсчёт путей с кэшем. Проверяйте себя на графах из 5–8 вершин, где ответ можно пересчитать перечислением.

Неделя 4: скорость и самопроверка

Цель — уложиться в 12 минут: 2 минуты на чтение условия, 5 на код, 2 на запуск и 3 на проверку. Заведите шаблон: чтение файла + пустое место под концовку. На каждом прогоне отдельно проверяйте, что взяли целую часть, а не округлили, и что подставили номера вершин из своего условия.

Проверьте себя прямо сейчас

Задания 23 ЕГЭ по информатике с мгновенной проверкой ответа — бесплатно и без регистрации.

Частые вопросы

Часто задаваемые вопросы

Умение решать алгоритмические задачи, связанные с анализом графов: построение оптимального пути между вершинами графа и определение количества различных путей между вершинами ориентированного ациклического графа. По кодификатору это элемент содержания 2.13 «Графы» и код требования 2.7. Тема появилась на этой позиции только в проекте КИМ 2027 года — до этого задание 23 проверяло умение анализировать ход исполнения алгоритма, и эта тема переехала на задание 13.

1 первичный балл по принципу «всё или ничего»: ответ либо совпадает с эталоном, либо задание оценивается в 0. По обобщённому плану варианта КИМ 2027 года на задание 23 отводится примерно 12 минут. Уровень сложности — повышенный. К заданию прилагается текстовый файл, и для решения нужна среда программирования.

Текстовым файлом. В каждой строке записаны два натуральных числа L и M — номера вершин, и одно положительное вещественное число W — вес ребра, ведущего из вершины L в вершину M. Количество строк равно количеству рёбер. Числа разделены произвольным ненулевым количеством пробелов и/или табуляций, поэтому строку нужно разбирать методом split() без аргументов. Вершины могут быть пронумерованы не подряд: номера доходят до 1000, но встречаются в файле не все.

Алгоритм Дейкстры: для каждой вершины хранится текущая оценка длины пути от старта, на каждом шаге берётся непросмотренная вершина с наименьшей оценкой, и её исходящие рёбра «расслабляются». Веса в задании 23 положительные, поэтому Дейкстра применима. Есть и более простой вариант: расслабить все рёбра подряд столько раз, сколько рёбер в файле (алгоритм Беллмана — Форда). При ограничении в 200 строк оба варианта работают за миллисекунды.

Динамикой по вершинам. Обозначьте через P[v] количество путей из вершины v в конечную вершину T. Тогда P[T] = 1, а для любой другой вершины P[v] равно сумме P[u] по всем рёбрам v → u. Ацикличность графа гарантирует, что каждая вершина посчитается ровно один раз, а кэш результатов превращает экспоненциальный перебор в линейный по числу рёбер. Если из вершины не выходит ни одного ребра, сумма по пустому списку даёт 0 — путей из неё в конец нет.

Нет. Условие требует записать целую часть длины кратчайшего пути, то есть отбросить дробную часть, а не округлить. Длина 7,5 даёт ответ 7, длина 10971,84 даёт 10971. В Python это int(x) или math.floor(x) для положительного числа; функция round() здесь неверна и обнулит задание. Во второй подзадаче — количество путей — округлять нечего, ответ и так целый.

Потому что граф ориентированный: строка «L M W» задаёт ребро только из L в M. Обратное ребро создаёт маршруты, которых в графе нет, и кратчайший путь получается короче настоящего. В задаче на количество путей последствия ещё хуже: граф перестаёт быть ациклическим, путей становится бесконечно много, и программа зацикливается.

10971. Приложенный файл содержит 200 строк — верхнюю границу из условия; номера вершин доходят до 998, реально встречаются 50 вершин, веса лежат в диапазоне от 44 до 9988. Кратчайший путь из вершины 1 в вершину 100 состоит из двенадцати рёбер и имеет длину ровно 10971. Для типового примера из восьми строк, приведённого в самом условии, верный ответ — 7.

Готовьтесь к КЕГЭ на Репет

Задание 23 выглядит сложным только из-за слова «граф». На деле это двадцать строк кода, которые пишутся один раз и работают на любом варианте. Освойте шаблон — и 12 минут превратятся в пять.